in src/Microsoft.VisualStudio.Composition/Configuration/AttributedPartDiscoveryV1.cs [361:415]
private static IReadOnlyDictionary<string, object?> GetExportMetadata(MemberInfo member)
{
Requires.NotNull(member, nameof(member));
var result = ImmutableDictionary.CreateBuilder<string, object?>();
foreach (var attribute in member.GetAttributes<Attribute>())
{
var exportMetadataAttribute = attribute as ExportMetadataAttribute;
if (exportMetadataAttribute != null)
{
if (exportMetadataAttribute.IsMultiple)
{
result[exportMetadataAttribute.Name] = AddElement(result.GetValueOrDefault(exportMetadataAttribute.Name) as Array, exportMetadataAttribute.Value, null);
}
else
{
result.Add(exportMetadataAttribute.Name, exportMetadataAttribute.Value);
}
}
else
{
Type attrType = attribute.GetType();
// Perf optimization, relies on short circuit evaluation, often a property attribute is an ExportAttribute
if (attrType != typeof(ExportAttribute) && attrType.GetTypeInfo().IsAttributeDefined<MetadataAttributeAttribute>(true))
{
var usage = attrType.GetTypeInfo().GetFirstAttribute<AttributeUsageAttribute>(true);
var properties = attribute.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var property in properties.Where(p => p.DeclaringType != typeof(Attribute) && p.DeclaringType != typeof(ExportAttribute)))
{
if (usage != null && usage.AllowMultiple)
{
result[property.Name] = AddElement(result.GetValueOrDefault(property.Name) as Array, property.GetValue(attribute), ReflectionHelpers.GetMemberType(property));
}
else
{
if (result.ContainsKey(property.Name))
{
string memberName = member.MemberType.HasFlag(MemberTypes.TypeInfo) || member.MemberType.HasFlag(MemberTypes.NestedType)
? ((TypeInfo)member).FullName!
: $"{member.DeclaringType?.FullName}.{member.Name}";
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Strings.DiscoveredIdenticalPropertiesInMetadataAttributesForPart, memberName, property.Name));
}
result.Add(property.Name, property.GetValue(attribute));
}
}
}
}
}
return result.ToImmutable();
}