File: System\ComponentModel\Composition\AttributedModel\AttributedModelDiscovery.cs
Web Access
Project: src\src\libraries\System.ComponentModel.Composition\src\System.ComponentModel.Composition.csproj (System.ComponentModel.Composition)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;
using System.ComponentModel.Composition.ReflectionModel;
using System.Composition.Diagnostics;
using System.Globalization;
using System.Reflection;
using Microsoft.Internal;
 
namespace System.ComponentModel.Composition.AttributedModel
{
    internal static class AttributedModelDiscovery
    {
        public static ComposablePartDefinition? CreatePartDefinitionIfDiscoverable(Type type, ICompositionElement? origin)
        {
            AttributedPartCreationInfo creationInfo = new AttributedPartCreationInfo(type, null, false, origin);
            if (!creationInfo.IsPartDiscoverable())
            {
                return null;
            }
 
            return new ReflectionComposablePartDefinition(creationInfo);
        }
 
        public static ReflectionComposablePartDefinition CreatePartDefinition(Type type, PartCreationPolicyAttribute? partCreationPolicy, bool ignoreConstructorImports, ICompositionElement? origin)
        {
            ArgumentNullException.ThrowIfNull(type);
 
            AttributedPartCreationInfo creationInfo = new AttributedPartCreationInfo(type, partCreationPolicy, ignoreConstructorImports, origin);
 
            return new ReflectionComposablePartDefinition(creationInfo);
        }
 
        public static ReflectionComposablePart CreatePart(object attributedPart)
        {
            ArgumentNullException.ThrowIfNull(attributedPart);
 
            // If given an instance then we want to pass the default composition options because we treat it as a shared part
            ReflectionComposablePartDefinition definition = AttributedModelDiscovery.CreatePartDefinition(attributedPart.GetType(), PartCreationPolicyAttribute.Shared, true, (ICompositionElement?)null);
 
            return new ReflectionComposablePart(definition, attributedPart);
        }
 
        public static ReflectionComposablePart CreatePart(object attributedPart, ReflectionContext reflectionContext)
        {
            ArgumentNullException.ThrowIfNull(attributedPart);
            ArgumentNullException.ThrowIfNull(reflectionContext);
 
            // If given an instance then we want to pass the default composition options because we treat it as a shared part
            var mappedType = reflectionContext.MapType(IntrospectionExtensions.GetTypeInfo(attributedPart.GetType()));
            if (mappedType.Assembly.ReflectionOnly)
            {
                throw new ArgumentException(SR.Format(SR.Argument_ReflectionContextReturnsReflectionOnlyType, nameof(reflectionContext)), nameof(reflectionContext));
            }
 
            ReflectionComposablePartDefinition definition = AttributedModelDiscovery.CreatePartDefinition(mappedType, PartCreationPolicyAttribute.Shared, true, (ICompositionElement?)null);
 
            return CreatePart(definition, attributedPart);
        }
 
        public static ReflectionComposablePart CreatePart(ComposablePartDefinition partDefinition, object attributedPart)
        {
            ArgumentNullException.ThrowIfNull(partDefinition);
            ArgumentNullException.ThrowIfNull(attributedPart);
 
            return new ReflectionComposablePart((ReflectionComposablePartDefinition)partDefinition, attributedPart);
        }
 
        public static ReflectionParameterImportDefinition CreateParameterImportDefinition(ParameterInfo parameter, ICompositionElement origin)
        {
            Requires.NotNull(parameter, nameof(parameter));
 
            ReflectionParameter reflectionParameter = parameter.ToReflectionParameter();
            IAttributedImport attributedImport = AttributedModelDiscovery.GetAttributedImport(reflectionParameter, parameter);
            ImportType importType = new ImportType(reflectionParameter.ReturnType, attributedImport.Cardinality);
 
            if (importType.IsPartCreator)
            {
                return new PartCreatorParameterImportDefinition(
                    new Lazy<ParameterInfo>(() => parameter),
                    origin,
                    new ContractBasedImportDefinition(
                        attributedImport.GetContractNameFromImport(importType),
                        attributedImport.GetTypeIdentityFromImport(importType),
                        CompositionServices.GetRequiredMetadata(importType.MetadataViewType),
                        attributedImport.Cardinality,
                        false,
                        true,
                        CreationPolicy.NonShared,
                        CompositionServices.GetImportMetadata(importType, attributedImport)));
            }
            else
            {
                return new ReflectionParameterImportDefinition(
                    new Lazy<ParameterInfo>(() => parameter),
                    attributedImport.GetContractNameFromImport(importType),
                    attributedImport.GetTypeIdentityFromImport(importType),
                    CompositionServices.GetRequiredMetadata(importType.MetadataViewType),
                    attributedImport.Cardinality,
                    attributedImport.RequiredCreationPolicy,
                    CompositionServices.GetImportMetadata(importType, attributedImport),
                    origin);
            }
        }
 
        public static ReflectionMemberImportDefinition CreateMemberImportDefinition(MemberInfo member, ICompositionElement origin)
        {
            Requires.NotNull(member, nameof(member));
 
            ReflectionWritableMember reflectionMember = member.ToReflectionWritableMember();
            IAttributedImport attributedImport = AttributedModelDiscovery.GetAttributedImport(reflectionMember, member);
            ImportType importType = new ImportType(reflectionMember.ReturnType, attributedImport.Cardinality);
 
            if (importType.IsPartCreator)
            {
                return new PartCreatorMemberImportDefinition(
                    new LazyMemberInfo(member),
                    origin,
                    new ContractBasedImportDefinition(
                        attributedImport.GetContractNameFromImport(importType),
                        attributedImport.GetTypeIdentityFromImport(importType),
                        CompositionServices.GetRequiredMetadata(importType.MetadataViewType),
                        attributedImport.Cardinality,
                        attributedImport.AllowRecomposition,
                        false,
                        CreationPolicy.NonShared,
                        CompositionServices.GetImportMetadata(importType, attributedImport)));
            }
            else
            {
                //Does this Import re-export the value if so, make it a rpe-requisite
                bool isPrerequisite = member.GetAttributes<ExportAttribute>().Length > 0;
                return new ReflectionMemberImportDefinition(
                    new LazyMemberInfo(member),
                    attributedImport.GetContractNameFromImport(importType),
                    attributedImport.GetTypeIdentityFromImport(importType),
                    CompositionServices.GetRequiredMetadata(importType.MetadataViewType),
                    attributedImport.Cardinality,
                    attributedImport.AllowRecomposition,
                    isPrerequisite,
                    attributedImport.RequiredCreationPolicy,
                    CompositionServices.GetImportMetadata(importType, attributedImport),
                    origin);
            }
        }
 
        private static IAttributedImport GetAttributedImport(ReflectionItem item, ICustomAttributeProvider attributeProvider)
        {
            IAttributedImport[] imports = attributeProvider.GetAttributes<IAttributedImport>(false);
 
            // For constructor parameters they may not have an ImportAttribute
            if (imports.Length == 0)
            {
                return new ImportAttribute();
            }
 
            if (imports.Length > 1)
            {
                CompositionTrace.MemberMarkedWithMultipleImportAndImportMany(item);
            }
 
            // Regardless of how many imports, always return the first one
            return imports[0];
        }
    }
}