in src/Microsoft.VisualStudio.Composition/Configuration/AttributedPartDiscoveryV1.cs [29:220]
protected override ComposablePartDefinition? CreatePart(Type partType, bool typeExplicitlyRequested)
{
Requires.NotNull(partType, nameof(partType));
var partTypeInfo = partType.GetTypeInfo();
// We want to ignore abstract classes, but we want to consider static classes.
// Static classes claim to be both abstract and sealed. So to ignore just abstract
// ones, we check that they are not sealed.
if (partTypeInfo.IsAbstract && !partTypeInfo.IsSealed)
{
return null;
}
BindingFlags everythingLocal = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
BindingFlags instanceLocal = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
// If the type is abstract only find local static exports
var exportBindingFlags = everythingLocal;
if (partTypeInfo.IsAbstract)
{
exportBindingFlags &= ~BindingFlags.Instance;
}
var declaredMethods = partType.GetMethods(exportBindingFlags); // methods can only export, not import
var declaredProperties = partType.GetProperties(everythingLocal);
var declaredFields = partType.GetFields(everythingLocal);
var allLocalMembers = declaredMethods.Concat<MemberInfo>(declaredProperties).Concat(declaredFields);
var exportingMembers = from member in allLocalMembers
from export in member.GetAttributes<ExportAttribute>()
select new KeyValuePair<MemberInfo, ExportAttribute>(member, export);
var exportedTypes = from export in partTypeInfo.GetAttributes<ExportAttribute>()
select new KeyValuePair<MemberInfo, ExportAttribute>(partTypeInfo, export);
var inheritedExportedTypes = from baseTypeOrInterface in partType.GetInterfaces().Concat(partType.EnumTypeAndBaseTypes().Skip(1))
where baseTypeOrInterface != typeof(object)
from export in baseTypeOrInterface.GetTypeInfo().GetAttributes<InheritedExportAttribute>()
select new KeyValuePair<MemberInfo, ExportAttribute>(baseTypeOrInterface.GetTypeInfo(), export);
var exportsByMember = (from export in exportingMembers.Concat(exportedTypes).Concat(inheritedExportedTypes)
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;
// Collect information for all imports.
var imports = ImmutableList.CreateBuilder<ImportDefinitionBinding>();
this.AddImportsFromMembers(declaredProperties, declaredFields, partTypeRef, imports);
Type? baseType = partTypeInfo.BaseType;
while (baseType != null && baseType != typeof(object))
{
this.AddImportsFromMembers(baseType.GetProperties(instanceLocal), baseType.GetFields(instanceLocal), partTypeRef, imports);
baseType = baseType.GetTypeInfo().BaseType;
}
var partCreationPolicy = CreationPolicy.Any;
var partCreationPolicyAttribute = partTypeInfo.GetFirstAttribute<PartCreationPolicyAttribute>();
if (partCreationPolicyAttribute != null)
{
partCreationPolicy = (CreationPolicy)partCreationPolicyAttribute.CreationPolicy;
}
var allExportsMetadata = ImmutableDictionary.CreateRange(PartCreationPolicyConstraint.GetExportMetadata(partCreationPolicy));
var inheritedExportContractNamesFromNonInterfaces = ImmutableHashSet.CreateBuilder<string>();
var exportDefinitions = ImmutableList.CreateBuilder<KeyValuePair<MemberInfo, ExportDefinition>>();
foreach (var export in exportsByMember)
{
var memberExportMetadata = allExportsMetadata.AddRange(GetExportMetadata(export.Key));
if (export.Key is MethodInfo method)
{
var exportAttributes = export.Value;
if (exportAttributes.Any())
{
foreach (var exportAttribute in exportAttributes)
{
Type exportedType = exportAttribute.ContractType ?? ReflectionHelpers.GetContractTypeForDelegate(method);
string contractName = string.IsNullOrEmpty(exportAttribute.ContractName) ? GetContractName(exportedType) : exportAttribute.ContractName!;
var exportMetadata = memberExportMetadata
.Add(CompositionConstants.ExportTypeIdentityMetadataName, ContractNameServices.GetTypeIdentity(exportedType));
var exportDefinition = new ExportDefinition(contractName, exportMetadata);
exportDefinitions.Add(new KeyValuePair<MemberInfo, ExportDefinition>(export.Key, exportDefinition));
}
}
}
else
{
MemberInfo exportingTypeOrPropertyOrField = export.Key;
Verify.Operation(export.Key is TypeInfo || !partTypeInfo.IsGenericTypeDefinition, Strings.ExportsOnMembersNotAllowedWhenDeclaringTypeGeneric);
Type exportSiteType = ReflectionHelpers.GetMemberType(exportingTypeOrPropertyOrField);
foreach (var exportAttribute in export.Value)
{
Type exportedType = exportAttribute.ContractType ?? partTypeAsGenericTypeDefinition ?? exportSiteType;
string contractName = string.IsNullOrEmpty(exportAttribute.ContractName) ? GetContractName(exportedType) : exportAttribute.ContractName!;
if (export.Key is TypeInfo && exportAttribute is InheritedExportAttribute)
{
if (inheritedExportContractNamesFromNonInterfaces.Contains(contractName))
{
// We already have an export with this contract name on this type (from a more derived type)
// using InheritedExportAttribute.
continue;
}
if (!((TypeInfo)export.Key).IsInterface)
{
inheritedExportContractNamesFromNonInterfaces.Add(contractName);
}
}
var exportMetadata = memberExportMetadata
.Add(CompositionConstants.ExportTypeIdentityMetadataName, ContractNameServices.GetTypeIdentity(exportedType));
var exportDefinition = new ExportDefinition(contractName, exportMetadata);
exportDefinitions.Add(new KeyValuePair<MemberInfo, ExportDefinition>(export.Key, exportDefinition));
}
}
}
MethodInfo? onImportsSatisfied = null;
if (typeof(IPartImportsSatisfiedNotification).IsAssignableFrom(partType))
{
onImportsSatisfied = OnImportsSatisfiedMethodInfo;
}
var importingConstructorParameters = ImmutableList.CreateBuilder<ImportDefinitionBinding>();
var importingCtor = GetImportingConstructor<ImportingConstructorAttribute>(partType, publicOnly: false);
if (importingCtor != null) // some parts have exports merely for metadata -- they can't be instantiated
{
foreach (var parameter in importingCtor.GetParameters())
{
var import = this.CreateImport(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 exportsOnType = exportDefinitions.Where(kv => kv.Key is TypeInfo).Select(kv => kv.Value).ToArray();
var exportsOnMembers = (from kv in exportDefinitions
where !(kv.Key is TypeInfo)
group kv.Value by kv.Key into byMember
select byMember).ToDictionary(g => MemberRef.Get(g.Key, this.Resolver), g => (IReadOnlyCollection<ExportDefinition>)g.ToArray());
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,
exportsOnMembers,
imports.ToImmutable(),
partCreationPolicy != CreationPolicy.NonShared ? string.Empty : null,
onImportsSatisfied is object ? ImmutableList.Create(MethodRef.Get(onImportsSatisfied, this.Resolver)) : ImmutableList<MethodRef>.Empty,
MethodRef.Get(importingCtor, this.Resolver),
importingCtor != null ? importingConstructorParameters.ToImmutable() : null, // some MEF parts are only for metadata
partCreationPolicy,
partCreationPolicy != CreationPolicy.NonShared,
assemblyNamesForMetadataAttributes);
}