250 lines
8.5 KiB
C#
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
|
|
}
|
|
}
|