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 LazyType { get { return new Lazy(m_type); } } #endregion #region Methods public IEnumerable GetExports(PartDefinition part) { foreach (var type in GetExports(m_type)) { foreach (var exportAttribute in type.GetAttributes(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(false)) { yield return CreateExport(part, type, inheritedExportAttribute); } } } public IEnumerable 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 GetExportMetadata(Type exportingType, ExportAttribute exportAttribute) { var metadata = new Dictionary(); 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(false); ImportType importType = new ImportType(member, importAttribute.Cardinality); var contractName = GetContractNameFromImport(importAttribute, importType); string typeIdentity = GetTypeIdentityFromImport(importType); IEnumerable 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 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 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 GetExports(Type type) { if (IsExport(type)) { yield return type; } } private static IEnumerable 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(false); } private static bool IsExport(ICustomAttributeProvider attributeProvider) { return attributeProvider.HasAttribute(false); } private static bool IsInheritedExport(ICustomAttributeProvider attributedProvider) { return attributedProvider.HasAttribute(false); } #endregion } }