Repository: dotnet/roslyn
File: src/VisualStudio/Core/Def/TaskList/VisualStudioDiagnosticIdCache.cs (C#)

Code before:
            listenerProvider);
    }
}

internal class VisualStudioDiagnosticIdCache : IWorkspaceService
{
    // This dictionary maps ProjectIds to a descriptor map.
    private readonly ConcurrentDictionary<ProjectId, ImmutableHashSet<string>> _projectIdToDiagnosticIdsCache = [];
    private readonly AsyncBatchingWorkQueue<ProjectId> _projectDescriptorRefreshQueue;

    private readonly Workspace _workspace;
    private readonly IDiagnosticAnalyzerService _analyzerService;
    private readonly IAsynchronousOperationListener _listener;

    public VisualStudioDiagnosticIdCache(Workspace workspace, IAsynchronousOperationListenerProvider? listenerProvider)
    {
        _workspace = workspace;
        _analyzerService = workspace.Services.GetRequiredService<IDiagnosticAnalyzerService>();
        _listener = listenerProvider?.GetListener(FeatureAttribute.DiagnosticService) ?? AsynchronousOperationListenerProvider.NullListener;

        _projectDescriptorRefreshQueue = new AsyncBatchingWorkQueue<ProjectId>(
            delay: DelayTimeSpan.Short,
            processBatchAsync: RefreshCachedDiagnosticIdsAsync,
            equalityComparer: EqualityComparer<ProjectId>.Default,
            asyncListener: _listener,
            cancellationToken: CancellationToken.None);

        _workspace.RegisterWorkspaceChangedHandler(WorkspaceChanged);

        foreach (var projectId in _workspace.CurrentSolution.ProjectIds)
        {
            _projectDescriptorRefreshQueue.AddWork(projectId);
        }
    }

    public bool TryGetDiagnosticIds(ProjectId projectId, [NotNullWhen(returnValue: true)] out ImmutableHashSet<string>? diagnosticIds)
        => _projectIdToDiagnosticIdsCache.TryGetValue(projectId, out diagnosticIds);

    private void WorkspaceChanged(WorkspaceChangeEventArgs e)
    {
        var workspaceChanges = e.NewSolution.GetChanges(e.OldSolution);

        foreach (var addedProject in workspaceChanges.GetAddedProjects())
        {
            _projectDescriptorRefreshQueue.AddWork(addedProject.Id);
        }

        foreach (var removedProject in workspaceChanges.GetRemovedProjects())
        {
            _projectDescriptorRefreshQueue.AddWork(removedProject.Id);
        }

Review comment (suggestion):
If you import IThreadingContext that has a DisposalToken you can use.

Code after:
        return new VisualStudioDiagnosticIdCache(
            workspaceServices.Workspace,
            threadingContext,
            listenerProvider);
    }
}

internal class VisualStudioDiagnosticIdCache : IWorkspaceService
{
    // This dictionary maps ProjectIds to a descriptor list.
    private readonly ConcurrentDictionary<ProjectId, ImmutableHashSet<string>> _projectIdToDiagnosticIdsCache = [];
    private readonly AsyncBatchingWorkQueue<ProjectId> _projectDescriptorRefreshQueue;

    private readonly Workspace _workspace;
    private readonly IDiagnosticAnalyzerService _analyzerService;
    private readonly IAsynchronousOperationListener _listener;

    public VisualStudioDiagnosticIdCache(
        Workspace workspace,
        IThreadingContext threadingContext,
        IAsynchronousOperationListenerProvider listenerProvider)
    {
        _workspace = workspace;
        _analyzerService = workspace.Services.GetRequiredService<IDiagnosticAnalyzerService>();
        _listener = listenerProvider.GetListener(FeatureAttribute.DiagnosticService);

        _projectDescriptorRefreshQueue = new AsyncBatchingWorkQueue<ProjectId>(
            delay: DelayTimeSpan.Short,
            processBatchAsync: RefreshCachedDiagnosticIdsAsync,
            equalityComparer: EqualityComparer<ProjectId>.Default,
            asyncListener: _listener,
            cancellationToken: threadingContext.DisposalToken);

        _workspace.RegisterWorkspaceChangedHandler(WorkspaceChanged);

        foreach (var projectId in _workspace.CurrentSolution.ProjectIds)
        {
            _projectDescriptorRefreshQueue.AddWork(projectId);
        }
    }

    public bool TryGetDiagnosticIds(ProjectId projectId, [NotNullWhen(returnValue: true)] out ImmutableHashSet<string>? diagnosticIds)
        => _projectIdToDiagnosticIdsCache.TryGetValue(projectId, out diagnosticIds);

    private void WorkspaceChanged(WorkspaceChangeEventArgs e)
    {
        var workspaceChanges = e.NewSolution.GetChanges(e.OldSolution);

        foreach (var addedProject in workspaceChanges.GetAddedProjects())
        {
            _projectDescriptorRefreshQueue.AddWork(addedProject.Id);