JD2022-TU1/main/tools/framework/JD.Reflection/MefImplementations/Model/Internal/ReflectionPartCreationInfo.cs

250 lines
8.5 KiB
C#

using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using JD.Kernel.StaticHelpers;
using JD.Reflection.Attributes;
using JD.Reflection.Interfaces;
using JD.Reflection.MefImplementations.Metadata;
using Type = System.Type;
namespace JD.Reflection.MefImplementations.Model.Internal
{
internal class ReflectionPartCreationInfo : IPartCreationInfo
{
#region Variables
private readonly Type m_type;
#endregion
#region Constructor
public ReflectionPartCreationInfo(Type type)
{
Throw.IfNull(type, "type");
m_type = type;
}
#endregion
#region Properties
public Lazy<Type> LazyType
{
get
{
return new Lazy<Type>(m_type);
}
}
#endregion
#region Methods
public IEnumerable<ExportDefinition> GetExports(PartDefinition part)
{
foreach (var type in GetExports(m_type))
{
foreach (var exportAttribute in type.GetAttributes<ExportAttribute>(false))
{
if (!(exportAttribute is InheritedExportAttribute && type.IsAbstract))
{
yield return CreateExport(part, type, exportAttribute);
}
}
}
foreach (var type in GetInheritedExports(m_type))
{
foreach (var inheritedExportAttribute in type.GetAttributes<InheritedExportAttribute>(false))
{
yield return CreateExport(part, type, inheritedExportAttribute);
}
}
}
public IEnumerable<ImportDefinition> GetImports(PartDefinition part)
{
return GetImportMembers(m_type).Select(member => CreateImport(part, member));
}
private ExportDefinition CreateExport(PartDefinition part, Type exportingType, ExportAttribute exportAttribute)
{
return new ExportDefinition(part, GetContractNameFromExport(exportingType, exportAttribute), GetExportMetadata(exportingType, exportAttribute));
}
private IDictionary<string, object> GetExportMetadata(Type exportingType, ExportAttribute exportAttribute)
{
var metadata = new Dictionary<string, object>();
string typeIdentity = GetTypeIdentityFromExport(exportingType, exportAttribute);
metadata.Add(ExportDefinition.ExportTypeIdentityMetadataKey, typeIdentity);
metadata.Add(ExportDefinition.TypeIdentityMetadataKey, ContractNameServices.GetTypeIdentity(m_type));
return metadata;
}
private static ImportDefinition CreateImport(PartDefinition part, MemberInfo member)
{
var importAttribute = member.TryGetAttribute<IImportAttribute>(false);
ImportType importType = new ImportType(member, importAttribute.Cardinality);
var contractName = GetContractNameFromImport(importAttribute, importType);
string typeIdentity = GetTypeIdentityFromImport(importType);
IEnumerable<RequiredMetadataItem> requiredMetadata = MetadataViewServices.GetRequiredMetadata(importType.MetadataViewType);
return new ImportDefinition(part, contractName, typeIdentity, importAttribute.Cardinality, new LazyMemberInfo(member), requiredMetadata);
}
private static string GetContractNameFromExport(Type exportingType, ExportAttribute export)
{
if (!string.IsNullOrEmpty(export.ContractName))
{
return export.ContractName;
}
if (export.ContractType != null)
{
return ContractNameServices.GetTypeIdentity(export.ContractType);
}
return ContractNameServices.GetTypeIdentity(exportingType);
}
private static string GetTypeIdentityFromExport(Type exportingType, ExportAttribute export)
{
if (export.ContractType != null)
{
return ContractNameServices.GetTypeIdentity(export.ContractType);
}
return ContractNameServices.GetTypeIdentity(exportingType);
}
private static string GetTypeIdentityFromImport(ImportType importType)
{
Type contractType = importType.ContractType;
return contractType == typeof(object) ? null : ContractNameServices.GetTypeIdentity(contractType);
}
private static IEnumerable<MemberInfo> GetImportMembers(Type type)
{
foreach (MemberInfo member in GetDeclaredOnlyImportMembers(type))
{
yield return member;
}
if (type.BaseType != null)
{
Type baseType = type.BaseType;
while (baseType != null && baseType != typeof(object))
{
foreach (MemberInfo member in GetDeclaredOnlyImportMembers(baseType))
{
yield return member;
}
baseType = baseType.BaseType;
}
}
}
private static IEnumerable<MemberInfo> GetDeclaredOnlyImportMembers(Type type)
{
const BindingFlags Flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
foreach (var member in type.GetFields(Flags))
{
if (IsImport(member))
{
yield return member;
}
}
foreach (var member in type.GetProperties(Flags))
{
if (IsImport(member))
{
yield return member;
}
}
}
private static string GetContractNameFromImport(IImportAttribute importAttribute, ImportType importType)
{
if (!string.IsNullOrEmpty(importAttribute.ContractName))
{
return importAttribute.ContractName;
}
return ContractNameServices.GetTypeIdentity(importType.ContractType);
}
private static IEnumerable<Type> GetExports(Type type)
{
if (IsExport(type))
{
yield return type;
}
}
private static IEnumerable<Type> GetInheritedExports(Type type)
{
// If the type is abstract we aren't interested in type level exports
if (type.IsAbstract)
{
yield break;
}
// The order of types returned here is important because it is used as a
// priority list of which InheritedExport to choose if multiple exists with
// the same contract name. Therefore ensure that we always return the types
// in the hiearchy from most derived to the lowest base type, followed
// by all the interfaces that this type implements.
Type currentType = type.BaseType;
if (currentType == null)
{
yield break;
}
// Stopping at object instead of null to help with performance. It is a noticable performance
// gain (~5%) if we don't have to try and pull the attributes we know don't exist on object.
// We also need the null check in case we're passed a type that doesn't live in the runtime context.
while (currentType != null && currentType != typeof(object))
{
if (IsInheritedExport(currentType))
{
yield return currentType;
}
currentType = currentType.BaseType;
}
foreach (Type iface in type.GetInterfaces())
{
if (IsInheritedExport(iface))
{
yield return iface;
}
}
}
private static bool IsImport(ICustomAttributeProvider attributeProvider)
{
return attributeProvider.HasAttribute<IImportAttribute>(false);
}
private static bool IsExport(ICustomAttributeProvider attributeProvider)
{
return attributeProvider.HasAttribute<ExportAttribute>(false);
}
private static bool IsInheritedExport(ICustomAttributeProvider attributedProvider)
{
return attributedProvider.HasAttribute<InheritedExportAttribute>(false);
}
#endregion
}
}