File: Mef\ExportProviderExtensions.cs
Web Access
Project: src\src\Razor\src\Razor\test\Microsoft.AspNetCore.Razor.Test.Common.Tooling\Microsoft.AspNetCore.Razor.Test.Common.Tooling.csproj (Microsoft.AspNetCore.Razor.Test.Common.Tooling)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections.Generic;
using System.Composition;
using System.Composition.Hosting.Core;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using Microsoft.VisualStudio.Composition;
 
namespace Microsoft.AspNetCore.Razor.Test.Common.Mef;
 
internal static class ExportProviderExtensions
{
    public static CompositionContext AsCompositionContext(this ExportProvider exportProvider)
    {
        return new CompositionContextShim(exportProvider);
    }
 
    private class CompositionContextShim : CompositionContext
    {
        private readonly ExportProvider _exportProvider;
 
        public CompositionContextShim(ExportProvider exportProvider)
        {
            _exportProvider = exportProvider;
        }
 
        public override bool TryGetExport(CompositionContract contract, [NotNullWhen(true)] out object? export)
        {
            var importMany = contract.MetadataConstraints.Contains(new KeyValuePair<string, object>("IsImportMany", true));
            var (contractType, metadataType, isLazy) = GetContractType(contract.ContractType, importMany);
 
            var method = (metadataType, isLazy) switch
            {
                (not null, true) => GetExportProviderGenericMethod(nameof(ExportProvider.GetExports), contractType, metadataType),
                (null, true) => GetExportProviderGenericMethod(nameof(ExportProvider.GetExports), contractType),
                (null, false) => GetExportProviderGenericMethod(nameof(ExportProvider.GetExportedValues), contractType),
                _ => null
            };
 
            if (method is null)
            {
                export = null;
                return false;
            }
 
            export = method.Invoke(_exportProvider, [contract.ContractName]);
            Assumes.NotNull(export);
 
            return true;
 
            static MethodInfo GetExportProviderGenericMethod(string methodName, params Type[] typeArguments)
            {
                var methodInfo = (from method in typeof(ExportProvider).GetTypeInfo().GetMethods()
                                  where method.Name == methodName
                                  where method.IsGenericMethod && method.GetGenericArguments().Length == typeArguments.Length
                                  where method.GetParameters().Length == 1 && method.GetParameters()[0].ParameterType == typeof(string)
                                  select method).Single();
 
                return methodInfo.MakeGenericMethod(typeArguments);
            }
        }
 
        private static (Type exportType, Type? metadataType, bool isLazy) GetContractType(Type contractType, bool importMany)
        {
            if (importMany)
            {
                if (contractType.IsConstructedGenericType)
                {
                    if (contractType.GetGenericTypeDefinition() == typeof(IList<>)
                        || contractType.GetGenericTypeDefinition() == typeof(ICollection<>)
                        || contractType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
                    {
                        contractType = contractType.GenericTypeArguments[0];
                    }
                }
                else if (contractType.IsArray)
                {
                    contractType = contractType.GetElementType().AssumeNotNull();
                }
            }
 
            if (contractType.IsConstructedGenericType)
            {
                if (contractType.GetGenericTypeDefinition() == typeof(Lazy<>))
                {
                    return (contractType.GenericTypeArguments[0], null, true);
                }
                else if (contractType.GetGenericTypeDefinition() == typeof(Lazy<,>))
                {
                    return (contractType.GenericTypeArguments[0], contractType.GenericTypeArguments[1], true);
                }
                else
                {
                    throw new NotSupportedException();
                }
            }
 
            return (contractType, null, false);
        }
    }
}