PageRenderTime 63ms CodeModel.GetById 38ms RepoModel.GetById 0ms app.codeStats 0ms

/src/MefContrib/Hosting/Conventions/ConventionPartCreator.cs

https://github.com/jorgemuza/MefContrib
C# | 213 lines | 125 code | 23 blank | 65 comment | 5 complexity | 8bd43f42bcf0ad7856675424ec2c3b1d MD5 | raw file
  1. namespace MefContrib.Hosting.Conventions
  2. {
  3. using System;
  4. using System.Collections.Generic;
  5. using System.ComponentModel.Composition.Hosting;
  6. using System.ComponentModel.Composition.Primitives;
  7. using System.ComponentModel.Composition.ReflectionModel;
  8. using System.Linq;
  9. using System.Reflection;
  10. using MefContrib.Hosting.Conventions.Configuration;
  11. /// <summary>
  12. ///
  13. /// </summary>
  14. public class ConventionPartCreator
  15. {
  16. /// <summary>
  17. /// Initializes a new instance of the <see cref="ConventionPartCreator"/> class.
  18. /// </summary>
  19. /// <param name="registry">The <see cref="IPartRegistry{T}"/> instance that should be used by the part creator.</param>
  20. /// <exception cref="ArgumentNullException">The provided <paramref name="registry"/> was <see langword="null"/>.</exception>
  21. public ConventionPartCreator(IPartRegistry<IContractService> registry)
  22. {
  23. if (registry == null)
  24. {
  25. throw new ArgumentNullException("registry", "The registry cannot be null.");
  26. }
  27. this.Registry = registry;
  28. }
  29. /// <summary>
  30. /// Gets the <see cref="IPartRegistry{T}"/> instance used by the part creator.
  31. /// </summary>
  32. /// <value>An <see cref="IPartRegistry{T}"/> instance.</value>
  33. public IPartRegistry<IContractService> Registry { get; private set; }
  34. /// <summary>
  35. /// Gets the <see cref="ITypeScanner"/> used by the <see cref="Registry"/>.
  36. /// </summary>
  37. /// <value>An <see cref="ITypeScanner"/> instance.</value>
  38. private ITypeScanner Scanner
  39. {
  40. get { return this.Registry.TypeScanner; }
  41. }
  42. /// <summary>
  43. /// Gets the <see cref="IContractService"/> used by the <see cref="Registry"/>.
  44. /// </summary>
  45. /// <value>An <see cref="IContractService"/> instance.</value>
  46. private IContractService ContractService
  47. {
  48. get { return this.Registry.ContractService; }
  49. }
  50. /// <summary>
  51. /// Creates <see cref="ComposablePartDefinition"/> instances from the <see cref="IPartConvention"/> and types.
  52. /// </summary>
  53. /// <returns>An <see cref="IEnumerable{T}"/>, containing <see cref="ComposablePartDefinition"/> instances.</returns>
  54. public IEnumerable<ComposablePartDefinition> CreateParts()
  55. {
  56. if (this.Scanner == null)
  57. {
  58. return Enumerable.Empty<ComposablePartDefinition>();
  59. }
  60. var definitionsFromConventions =
  61. from convention in this.Registry.GetConventions()
  62. from type in this.Scanner.GetTypes(convention.Condition)
  63. select CreatePartDefinition(convention, type);
  64. return definitionsFromConventions.ToList();
  65. }
  66. /// <summary>
  67. /// Creates <see cref="ExportDefinition"/> instance from the provided <see cref="IExportConvention"/> instances and type.
  68. /// </summary>
  69. /// <param name="exportConventions">An <see cref="IEnumerable{T}"/> of <see cref="IExportConvention"/> instances that should be used to create the <see cref="ExportDefinition"/> instances.</param>
  70. /// <param name="type">The <see cref="Type"/> for which the <see cref="ExportDefinition"/> instances should be created.</param>
  71. /// <returns>An <see cref="IEnumerable{T}"/> of <see cref="ExportDefinition"/> instances.</returns>
  72. private IEnumerable<ExportDefinition> CreateExportDefinitions(IEnumerable<IExportConvention> exportConventions, Type type)
  73. {
  74. var exportDefinitionsFromConvention =
  75. from exportConvention in exportConventions
  76. from member in exportConvention.Members.Invoke(type)
  77. select ReflectionModelServices.CreateExportDefinition(
  78. member.ToLazyMemberInfo(),
  79. this.ContractService.GetExportContractName(exportConvention, member),
  80. new Lazy<IDictionary<string, object>>(() => GetExportDefinitionMetadata(exportConvention, member)),
  81. null);
  82. return exportDefinitionsFromConvention.ToList();
  83. }
  84. /// <summary>
  85. /// Creates <see cref="ImportDefinition"/> instance from the provided <see cref="IImportConvention"/> instances and type.
  86. /// </summary>
  87. /// <param name="importConventions">An <see cref="IEnumerable{T}"/> of <see cref="IImportConvention"/> instances that should be used to create the <see cref="ImportDefinition"/> instances.</param>
  88. /// <param name="type">The <see cref="Type"/> for which the <see cref="ImportDefinition"/> instances should be created.</param>
  89. /// <returns>An <see cref="IEnumerable{T}"/> of <see cref="ImportDefinition"/> instances.</returns>
  90. private IEnumerable<ImportDefinition> CreateImportDefinitions(IEnumerable<IImportConvention> importConventions, Type type)
  91. {
  92. var importDefinitionsFromConvention = new List<ImportDefinition>();
  93. foreach (var importConvention in importConventions)
  94. {
  95. foreach (var member in importConvention.Members.Invoke(type))
  96. {
  97. if (member is ConstructorInfo)
  98. {
  99. importDefinitionsFromConvention.AddRange(((ConstructorInfo)member).GetParameters().Select(parameter => GetImportParameterDefinition(importConvention, parameter)));
  100. }
  101. else
  102. {
  103. importDefinitionsFromConvention.Add(GetImportDefinition(importConvention, member));
  104. }
  105. }
  106. }
  107. return importDefinitionsFromConvention.ToList();
  108. }
  109. /// <summary>
  110. /// Gets an <see cref="ImportDefinition"/> for a <see cref="ParameterInfo"/> instance using the provided <see cref="IImportConvention"/> instance.
  111. /// </summary>
  112. /// <param name="importConvention"><see cref="IImportConvention"/> instances that should be used to create the <see cref="ImportDefinition"/> instances.</param>
  113. /// <param name="parameter">The <see cref="ParameterInfo"/> for which the <see cref="ImportDefinition"/> instances should be created.</param>
  114. /// <returns>An <see cref="ImportDefinition"/> instance.</returns>
  115. private ImportDefinition GetImportParameterDefinition(IImportConvention importConvention, ParameterInfo parameter)
  116. {
  117. var actualType =
  118. parameter.ParameterType.GetActualType();
  119. return ReflectionModelServices.CreateImportDefinition(
  120. new Lazy<ParameterInfo>(() => parameter),
  121. this.ContractService.GetImportContractName(importConvention, actualType),
  122. this.ContractService.GetImportTypeIdentity(importConvention, actualType),
  123. null,
  124. parameter.ParameterType.GetCardinality(importConvention.AllowDefaultValue),
  125. importConvention.CreationPolicy,
  126. null);
  127. }
  128. /// <summary>
  129. /// Gets an <see cref="ImportDefinition"/> for a <see cref="MemberInfo"/> instance using the provided <see cref="IImportConvention"/> instance.
  130. /// </summary>
  131. /// <param name="importConvention"><see cref="IImportConvention"/> instances that should be used to create the <see cref="ImportDefinition"/> instances.</param>
  132. /// <param name="member">The <see cref="MemberInfo"/> for which the <see cref="ImportDefinition"/> instances should be created.</param>
  133. /// <returns>An <see cref="ImportDefinition"/> instance.</returns>
  134. private ImportDefinition GetImportDefinition(IImportConvention importConvention, MemberInfo member)
  135. {
  136. return ReflectionModelServices.CreateImportDefinition(
  137. member.ToLazyMemberInfo(),
  138. this.ContractService.GetImportContractName(importConvention, member),
  139. this.ContractService.GetImportTypeIdentity(importConvention, member),
  140. importConvention.RequiredMetadata.Select(x => new KeyValuePair<string, Type>(x.Name, x.Type)),
  141. member.GetCardinality(importConvention.AllowDefaultValue),
  142. importConvention.Recomposable,
  143. importConvention.CreationPolicy,
  144. null);
  145. }
  146. /// <summary>
  147. /// Create a <see cref="ComposablePartDefinition"/> for a specified type using the provided <see cref="IPartConvention"/>.
  148. /// </summary>
  149. /// <param name="convention">The <see cref="IPartConvention"/> instance which is used to create the <see cref="ComposablePartDefinition"/>.</param>
  150. /// <param name="type">The <see cref="Type"/> for which the <see cref="ComposablePartDefinition"/> should be created.</param>
  151. /// <returns>A <see cref="ComposablePartDefinition"/> instance.</returns>
  152. private ComposablePartDefinition CreatePartDefinition(IPartConvention convention, Type type)
  153. {
  154. return ReflectionModelServices.CreatePartDefinition(
  155. new Lazy<Type>(() => type),
  156. false,
  157. new Lazy<IEnumerable<ImportDefinition>>(() => CreateImportDefinitions(convention.Imports, type)),
  158. new Lazy<IEnumerable<ExportDefinition>>(() => CreateExportDefinitions(convention.Exports, type)),
  159. new Lazy<IDictionary<string, object>>(() => GetPartDefinitionMetadata(convention)),
  160. null);
  161. }
  162. /// <summary>
  163. /// Gets the metadata for the provided <see cref="IExportConvention"/>.
  164. /// </summary>
  165. /// <param name="exportConvention">The <see cref="IExportConvention"/> that the metadata should be retrieved for.</param>
  166. /// <param name="member">The <see cref="MemberInfo"/> that is being exported.</param>
  167. /// <returns>An <see cref="IDictionary{TKey,TValue}"/> containing the metadata for the export.</returns>
  168. private IDictionary<string, object> GetExportDefinitionMetadata(IExportConvention exportConvention, MemberInfo member)
  169. {
  170. var exportDefinitionMetadata =
  171. exportConvention.Metadata.ToMetadataDictionary();
  172. exportDefinitionMetadata.Add(
  173. CompositionConstants.ExportTypeIdentityMetadataName,
  174. this.ContractService.GetExportTypeIdentity(exportConvention, member));
  175. return exportDefinitionMetadata;
  176. }
  177. /// <summary>
  178. /// Gets the metadata for the provided <see cref="IPartConvention"/>.
  179. /// </summary>
  180. /// <param name="partConvention">The <see cref="IPartConvention"/> that the metadata should be retrieved for.</param>
  181. /// <returns>An <see cref="IDictionary{TKey,TValue}"/> containing the metadata for the part.</returns>
  182. private static IDictionary<string, object> GetPartDefinitionMetadata(IPartConvention partConvention)
  183. {
  184. var partDefinitionMetadata =
  185. partConvention.Metadata.ToMetadataDictionary();
  186. partDefinitionMetadata.Add(CompositionConstants.PartCreationPolicyMetadataName, partConvention.CreationPolicy);
  187. return partDefinitionMetadata;
  188. }
  189. }
  190. }