protected override ComposablePartDefinition? CreatePart()

in src/Microsoft.VisualStudio.Composition/Configuration/AttributedPartDiscovery.cs [49:246]


        protected override ComposablePartDefinition? CreatePart(Type partType, bool typeExplicitlyRequested)
        {
            Requires.NotNull(partType, nameof(partType));

            var partTypeInfo = partType.GetTypeInfo();
            if (!typeExplicitlyRequested)
            {
                bool isPublic = partType.IsNested ? partTypeInfo.IsNestedPublic : partTypeInfo.IsPublic;
                if (!this.IsNonPublicSupported && !isPublic)
                {
                    // Skip non-public types.
                    return null;
                }
            }

            BindingFlags instanceLocal = BindingFlags.DeclaredOnly | BindingFlags.Instance | this.PublicVsNonPublicFlags;
            var declaredProperties = partTypeInfo.GetProperties(instanceLocal);
            var exportingProperties = from member in declaredProperties
                                      from export in member.GetAttributes<ExportAttribute>()
                                      where member.GetMethod != null // MEFv2 quietly omits exporting properties with no getter
                                      select new KeyValuePair<MemberInfo, ExportAttribute>(member, export);
            var exportedTypes = from export in partTypeInfo.GetAttributes<ExportAttribute>()
                                select new KeyValuePair<MemberInfo, ExportAttribute>(partTypeInfo, export);
            var exportsByMember = (from export in exportingProperties.Concat(exportedTypes)
                                   group export.Value by export.Key into exportsByType
                                   select exportsByType).Select(g => new KeyValuePair<MemberInfo, ExportAttribute[]>(g.Key, g.ToArray())).ToArray();

            if (exportsByMember.Length == 0)
            {
                return null;
            }

            // Check for PartNotDiscoverable only after we've established it's an interesting part.
            // This optimizes for the fact that most types have no exports, in which case it's not a discoverable
            // part anyway. Checking for the PartNotDiscoverableAttribute first, which is rarely defined,
            // doesn't usually pay for itself in terms of short-circuiting. But it does add an extra
            // attribute to look for that we don't need to find for all the types that have no export attributes either.
            if (!typeExplicitlyRequested && partTypeInfo.IsAttributeDefined<PartNotDiscoverableAttribute>())
            {
                return null;
            }

            foreach (var exportingMember in exportsByMember)
            {
                this.ThrowOnInvalidExportingMember(exportingMember.Key);
            }

            TypeRef partTypeRef = TypeRef.Get(partType, this.Resolver);
            Type? partTypeAsGenericTypeDefinition = partTypeInfo.IsGenericType ? partType.GetGenericTypeDefinition() : null;

            string? sharingBoundary = null;
            var sharedAttribute = partTypeInfo.GetFirstAttribute<SharedAttribute>();
            if (sharedAttribute != null)
            {
                sharingBoundary = sharedAttribute.SharingBoundary ?? string.Empty;
            }

            CreationPolicy partCreationPolicy = sharingBoundary != null ? CreationPolicy.Shared : CreationPolicy.NonShared;
            var allExportsMetadata = ImmutableDictionary.CreateRange(PartCreationPolicyConstraint.GetExportMetadata(partCreationPolicy));

            var exportsOnType = ImmutableList.CreateBuilder<ExportDefinition>();
            var exportsOnMembers = ImmutableDictionary.CreateBuilder<MemberRef, IReadOnlyCollection<ExportDefinition>>();

            foreach (var export in exportsByMember)
            {
                var member = export.Key;
                var memberExportMetadata = allExportsMetadata.AddRange(this.GetExportMetadata(member));

                if (member is TypeInfo)
                {
                    foreach (var exportAttribute in export.Value)
                    {
                        Type exportedType = exportAttribute.ContractType ?? partTypeAsGenericTypeDefinition ?? partType;
                        ExportDefinition exportDefinition = CreateExportDefinition(memberExportMetadata, exportAttribute, exportedType);
                        exportsOnType.Add(exportDefinition);
                    }
                }
                else // property
                {
                    var property = (PropertyInfo)member;
                    Verify.Operation(!partTypeInfo.IsGenericTypeDefinition, Strings.ExportsOnMembersNotAllowedWhenDeclaringTypeGeneric);
                    var exportDefinitions = ImmutableList.CreateBuilder<ExportDefinition>();
                    foreach (var exportAttribute in export.Value)
                    {
                        Type exportedType = exportAttribute.ContractType ?? property.PropertyType;
                        ExportDefinition exportDefinition = CreateExportDefinition(memberExportMetadata, exportAttribute, exportedType);
                        exportDefinitions.Add(exportDefinition);
                    }

                    exportsOnMembers.Add(MemberRef.Get(member, this.Resolver), exportDefinitions.ToImmutable());
                }
            }

            var imports = ImmutableList.CreateBuilder<ImportDefinitionBinding>();
            AddImportsFromMembers(declaredProperties, partTypeRef, imports);
            Type? baseType = partTypeInfo.BaseType;
            while (baseType != null && baseType != typeof(object))
            {
                AddImportsFromMembers(baseType.GetProperties(instanceLocal), partTypeRef, imports);
                baseType = baseType.GetTypeInfo().BaseType;
            }

            void AddImportsFromMembers(PropertyInfo[] declaredProperties, TypeRef partTypeRef, IList<ImportDefinitionBinding> imports)
            {
                foreach (var member in declaredProperties)
                {
                    try
                    {
                        var importAttribute = member.GetFirstAttribute<ImportAttribute>();
                        var importManyAttribute = member.GetFirstAttribute<ImportManyAttribute>();
                        Requires.Argument(!(importAttribute != null && importManyAttribute != null), nameof(partType), Strings.MemberContainsBothImportAndImportMany, member.Name);

                        var importConstraints = GetImportConstraints(member);
                        ImportDefinition? importDefinition;
                        if (this.TryCreateImportDefinition(ReflectionHelpers.GetMemberType(member), member, importConstraints, out importDefinition))
                        {
                            var importDefinitionBinding = new ImportDefinitionBinding(
                                importDefinition,
                                partTypeRef,
                                MemberRef.Get(member, this.Resolver),
                                TypeRef.Get(member.PropertyType, this.Resolver),
                                TypeRef.Get(GetImportingSiteTypeWithoutCollection(importDefinition, member.PropertyType), this.Resolver));
                            imports.Add(importDefinitionBinding);
                        }
                    }
                    catch (Exception ex)
                    {
                        throw ThrowErrorScanningMember(member, ex);
                    }
                }
            }

            // MEFv2 is willing to find `internal` OnImportsSatisfied methods, so we should too regardless of our NonPublic flag.
            var onImportsSatisfied = ImmutableList.CreateBuilder<MethodRef>();
            Type? currentType = partTypeInfo;
            while (currentType is object && currentType != typeof(object))
            {
                foreach (var method in currentType.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
                {
                    try
                    {
                        if (method.IsAttributeDefined<OnImportsSatisfiedAttribute>())
                        {
                            Verify.Operation(method.GetParameters().Length == 0, Strings.OnImportsSatisfiedTakeNoParameters);
                            onImportsSatisfied.Add(MethodRef.Get(method, this.Resolver));
                        }
                    }
                    catch (Exception ex)
                    {
                        throw ThrowErrorScanningMember(method, ex);
                    }
                }

                currentType = currentType.GetTypeInfo().BaseType;
            }

            var importingConstructorParameters = ImmutableList.CreateBuilder<ImportDefinitionBinding>();
            var importingCtor = GetImportingConstructor<ImportingConstructorAttribute>(partType, publicOnly: !this.IsNonPublicSupported);
            Verify.Operation(importingCtor != null, Strings.NoImportingConstructorFound);
            foreach (var parameter in importingCtor.GetParameters())
            {
                var import = this.CreateImport(parameter, GetImportConstraints(parameter));
                if (import.ImportDefinition.Cardinality == ImportCardinality.ZeroOrMore)
                {
                    Verify.Operation(PartDiscovery.IsImportManyCollectionTypeCreateable(import), Strings.CollectionMustBePublicAndPublicCtorWhenUsingImportingCtor);
                }

                importingConstructorParameters.Add(import);
            }

            var partMetadata = ImmutableDictionary.CreateBuilder<string, object?>();
            foreach (var partMetadataAttribute in partTypeInfo.GetAttributes<PartMetadataAttribute>())
            {
                partMetadata[partMetadataAttribute.Name] = partMetadataAttribute.Value;
            }

            var assemblyNamesForMetadataAttributes = ImmutableHashSet.CreateBuilder<AssemblyName>(ByValueEquality.AssemblyName);
            foreach (var export in exportsByMember)
            {
                GetAssemblyNamesFromMetadataAttributes<MetadataAttributeAttribute>(export.Key, assemblyNamesForMetadataAttributes);
            }

            return new ComposablePartDefinition(
                TypeRef.Get(partType, this.Resolver),
                partMetadata.ToImmutable(),
                exportsOnType.ToImmutable(),
                exportsOnMembers.ToImmutable(),
                imports.ToImmutable(),
                sharingBoundary,
                onImportsSatisfied.ToImmutable(),
                MethodRef.Get(importingCtor, this.Resolver),
                importingConstructorParameters.ToImmutable(),
                partCreationPolicy,
                isSharingBoundaryInferred: false,
                extraInputAssemblies: assemblyNamesForMetadataAttributes);

            static Exception ThrowErrorScanningMember(MemberInfo member, Exception ex) => throw new PartDiscoveryException(string.Format(CultureInfo.CurrentCulture, Strings.ErrorWhileScanningMember, member.Name), ex);
        }