File: Internal\ExtensionMessageHandlerFactory.cs
Web Access
Project: src\src\Tools\ExternalAccess\Extensions\Microsoft.CodeAnalysis.ExternalAccess.Extensions.csproj (Microsoft.CodeAnalysis.ExternalAccess.Extensions)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using System.Collections.Immutable;
using System.Composition;
using System.Reflection;
using System.Threading;
using Microsoft.CodeAnalysis.ExternalAccess.Extensions;
using Microsoft.CodeAnalysis.Host.Mef;
 
namespace Microsoft.CodeAnalysis.Extensions;
 
[ExportWorkspaceService(typeof(IExtensionMessageHandlerFactory)), Shared]
[method: ImportingConstructor]
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
internal sealed class ExtensionMessageHandlerFactory() : IExtensionMessageHandlerFactory
{
    public ImmutableArray<IExtensionMessageHandlerWrapper<Document>> CreateDocumentMessageHandlers(
        Assembly assembly, string extensionIdentifier, CancellationToken cancellationToken)
        => CreateWorkspaceHandlers(
            assembly,
            typeof(IExtensionDocumentMessageHandler<,>),
            (handler, handlerInterface) => new ExtensionDocumentMessageHandlerWrapper(handler, handlerInterface, extensionIdentifier),
            cancellationToken);
 
    public ImmutableArray<IExtensionMessageHandlerWrapper<Solution>> CreateWorkspaceMessageHandlers(
        Assembly assembly, string extensionIdentifier, CancellationToken cancellationToken)
        => CreateWorkspaceHandlers(
            assembly,
            typeof(IExtensionWorkspaceMessageHandler<,>),
            (handler, handlerInterface) => new ExtensionWorkspaceMessageHandlerWrapper(handler, handlerInterface, extensionIdentifier),
            cancellationToken);
 
    private static ImmutableArray<IExtensionMessageHandlerWrapper<TArgument>> CreateWorkspaceHandlers<TArgument>(
        Assembly assembly,
        Type unboundInterfaceType,
        Func<object, Type, IExtensionMessageHandlerWrapper<TArgument>> wrapperCreator,
        CancellationToken cancellationToken)
    {
        var resultBuilder = ImmutableArray.CreateBuilder<IExtensionMessageHandlerWrapper<TArgument>>();
 
        foreach (var candidateType in assembly.GetTypes())
        {
            cancellationToken.ThrowIfCancellationRequested();
 
            if (candidateType.IsAbstract || candidateType.IsGenericType)
                continue;
 
            Type? boundInterfaceType = null;
            foreach (var interfaceType in candidateType.GetInterfaces())
            {
                if (interfaceType.IsGenericType &&
                    !interfaceType.IsGenericTypeDefinition &&
                    interfaceType.GetGenericTypeDefinition() == unboundInterfaceType)
                {
                    if (boundInterfaceType is not null)
                        throw new InvalidOperationException(string.Format(ExternalAccessExtensionsResources.Type_0_implements_interface_1_more_than_once, candidateType.FullName, unboundInterfaceType.Name));
 
                    boundInterfaceType = interfaceType;
                }
            }
 
            if (boundInterfaceType == null)
                continue;
 
            var handler = Activator.CreateInstance(candidateType)
                ?? throw new InvalidOperationException(string.Format(ExternalAccessExtensionsResources.Cannot_create_0, candidateType.FullName));
 
            resultBuilder.Add(wrapperCreator(handler, boundInterfaceType));
        }
 
        return resultBuilder.ToImmutable();
    }
}