PageRenderTime 47ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/GenericSpecializationPartCreationInfo.cs

https://bitbucket.org/danipen/mono
C# | 564 lines | 455 code | 93 blank | 16 comment | 61 complexity | 079fc7893459e11cbf85775cfff5b7d6 MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. // -----------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. // -----------------------------------------------------------------------
  4. using System;
  5. using System.Collections.Generic;
  6. using System.ComponentModel.Composition.Primitives;
  7. using System.Diagnostics.CodeAnalysis;
  8. using System.Globalization;
  9. using System.Linq;
  10. using System.Reflection;
  11. using Microsoft.Internal;
  12. using Microsoft.Internal.Collections;
  13. using System.Diagnostics.Contracts;
  14. using System.Threading;
  15. using System.ComponentModel.Composition.Hosting;
  16. namespace System.ComponentModel.Composition.ReflectionModel
  17. {
  18. internal class GenericSpecializationPartCreationInfo : IReflectionPartCreationInfo
  19. {
  20. private readonly IReflectionPartCreationInfo _originalPartCreationInfo;
  21. private readonly ReflectionComposablePartDefinition _originalPart;
  22. private readonly Type[] _specialization;
  23. private readonly string[] _specializationIdentities;
  24. private IEnumerable<ExportDefinition> _exports;
  25. private IEnumerable<ImportDefinition> _imports;
  26. private readonly Lazy<Type> _lazyPartType;
  27. private List<LazyMemberInfo> _members;
  28. private List<Lazy<ParameterInfo>> _parameters;
  29. private Dictionary<LazyMemberInfo, MemberInfo[]> _membersTable;
  30. private Dictionary<Lazy<ParameterInfo>, ParameterInfo> _parametersTable;
  31. private ConstructorInfo _constructor;
  32. private object _lock = new object();
  33. public GenericSpecializationPartCreationInfo(IReflectionPartCreationInfo originalPartCreationInfo, ReflectionComposablePartDefinition originalPart, Type[] specialization)
  34. {
  35. Assumes.NotNull(originalPartCreationInfo);
  36. Assumes.NotNull(specialization);
  37. Assumes.NotNull(originalPart);
  38. this._originalPartCreationInfo = originalPartCreationInfo;
  39. this._originalPart = originalPart;
  40. this._specialization = specialization;
  41. this._specializationIdentities = new string[this._specialization.Length];
  42. for (int i = 0; i < this._specialization.Length; i++)
  43. {
  44. this._specializationIdentities[i] = AttributedModelServices.GetTypeIdentity(this._specialization[i]);
  45. }
  46. this._lazyPartType = new Lazy<Type>(
  47. () => this._originalPartCreationInfo.GetPartType().MakeGenericType(specialization),
  48. LazyThreadSafetyMode.PublicationOnly);
  49. }
  50. public ReflectionComposablePartDefinition OriginalPart
  51. {
  52. get
  53. {
  54. return this._originalPart;
  55. }
  56. }
  57. public Type GetPartType()
  58. {
  59. return this._lazyPartType.Value;
  60. }
  61. public Lazy<Type> GetLazyPartType()
  62. {
  63. return this._lazyPartType;
  64. }
  65. public ConstructorInfo GetConstructor()
  66. {
  67. if (this._constructor == null)
  68. {
  69. ConstructorInfo genericConstuctor = this._originalPartCreationInfo.GetConstructor();
  70. ConstructorInfo result = null;
  71. if (genericConstuctor != null)
  72. {
  73. foreach (ConstructorInfo constructor in this.GetPartType().GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
  74. {
  75. if (constructor.MetadataToken == genericConstuctor.MetadataToken)
  76. {
  77. result = constructor;
  78. break;
  79. }
  80. }
  81. }
  82. Thread.MemoryBarrier();
  83. lock (this._lock)
  84. {
  85. if (this._constructor == null)
  86. {
  87. this._constructor = result;
  88. }
  89. }
  90. }
  91. return this._constructor;
  92. }
  93. public IDictionary<string, object> GetMetadata()
  94. {
  95. var originalMetadata = new Dictionary<string, object>(this._originalPartCreationInfo.GetMetadata(), StringComparers.MetadataKeyNames);
  96. originalMetadata.Remove(CompositionConstants.IsGenericPartMetadataName);
  97. originalMetadata.Remove(CompositionConstants.GenericPartArityMetadataName);
  98. originalMetadata.Remove(CompositionConstants.GenericParameterConstraintsMetadataName);
  99. originalMetadata.Remove(CompositionConstants.GenericParameterAttributesMetadataName);
  100. return originalMetadata;
  101. }
  102. private MemberInfo[] GetAccessors(LazyMemberInfo originalLazyMember)
  103. {
  104. this.BuildTables();
  105. Assumes.NotNull(this._membersTable);
  106. return this._membersTable[originalLazyMember];
  107. }
  108. private ParameterInfo GetParameter(Lazy<ParameterInfo> originalParameter)
  109. {
  110. this.BuildTables();
  111. Assumes.NotNull(this._parametersTable);
  112. return this._parametersTable[originalParameter];
  113. }
  114. private void BuildTables()
  115. {
  116. if (this._membersTable != null)
  117. {
  118. return;
  119. }
  120. this.PopulateImportsAndExports();
  121. List<LazyMemberInfo> members = null;
  122. List<Lazy<ParameterInfo>> parameters = null;
  123. lock (this._lock)
  124. {
  125. if (this._membersTable == null)
  126. {
  127. members = this._members;
  128. parameters = this._parameters;
  129. Assumes.NotNull(members);
  130. }
  131. }
  132. //
  133. // Get all members that can be of interest and extract their MetadataTokens
  134. //
  135. Dictionary<LazyMemberInfo, MemberInfo[]> membersTable = this.BuildMembersTable(members);
  136. Dictionary<Lazy<ParameterInfo>, ParameterInfo> parametersTable = this.BuildParametersTable(parameters);
  137. lock (this._lock)
  138. {
  139. if (this._membersTable == null)
  140. {
  141. this._membersTable = membersTable;
  142. this._parametersTable = parametersTable;
  143. Thread.MemoryBarrier();
  144. this._parameters = null;
  145. this._members = null;
  146. }
  147. }
  148. }
  149. private Dictionary<LazyMemberInfo, MemberInfo[]> BuildMembersTable(List<LazyMemberInfo> members)
  150. {
  151. Assumes.NotNull(members);
  152. Dictionary<LazyMemberInfo, MemberInfo[]> membersTable = new Dictionary<LazyMemberInfo, MemberInfo[]>();
  153. Dictionary<int, MemberInfo> specializedPartMembers = new Dictionary<int, MemberInfo>();
  154. Type closedGenericPartType = this.GetPartType();
  155. specializedPartMembers[closedGenericPartType.MetadataToken] = closedGenericPartType;
  156. foreach (MethodInfo method in closedGenericPartType.GetAllMethods())
  157. {
  158. specializedPartMembers[method.MetadataToken] = method;
  159. }
  160. foreach (FieldInfo field in closedGenericPartType.GetAllFields())
  161. {
  162. specializedPartMembers[field.MetadataToken] = field;
  163. }
  164. //
  165. // Now go through the members table and resolve them into the new closed type based on the tokens
  166. //
  167. foreach (LazyMemberInfo lazyMemberInfo in members)
  168. {
  169. MemberInfo[] genericAccessors = lazyMemberInfo.GetAccessors();
  170. MemberInfo[] accessors = new MemberInfo[genericAccessors.Length];
  171. for (int i = 0; i < genericAccessors.Length; i++)
  172. {
  173. // GENTODO - error case? Very unlikely, but still?
  174. accessors[i] = (genericAccessors[i] != null) ? specializedPartMembers[genericAccessors[i].MetadataToken] : null;
  175. }
  176. membersTable[lazyMemberInfo] = accessors;
  177. }
  178. return membersTable;
  179. }
  180. private Dictionary<Lazy<ParameterInfo>, ParameterInfo> BuildParametersTable(List<Lazy<ParameterInfo>> parameters)
  181. {
  182. if (parameters != null)
  183. {
  184. Dictionary<Lazy<ParameterInfo>, ParameterInfo> parametersTable = new Dictionary<Lazy<ParameterInfo>, ParameterInfo>();
  185. // GENTODO - error case
  186. ParameterInfo[] constructorParameters = this.GetConstructor().GetParameters();
  187. foreach (var lazyParameter in parameters)
  188. {
  189. parametersTable[lazyParameter] = constructorParameters[lazyParameter.Value.Position];
  190. }
  191. return parametersTable;
  192. }
  193. else
  194. {
  195. return null;
  196. }
  197. }
  198. private List<ImportDefinition> PopulateImports(List<LazyMemberInfo> members, List<Lazy<ParameterInfo>> parameters)
  199. {
  200. List<ImportDefinition> imports = new List<ImportDefinition>();
  201. foreach (ImportDefinition originalImport in this._originalPartCreationInfo.GetImports())
  202. {
  203. ReflectionImportDefinition reflectionImport = originalImport as ReflectionImportDefinition;
  204. if (reflectionImport == null)
  205. {
  206. // we always ignore these
  207. continue;
  208. }
  209. imports.Add(this.TranslateImport(reflectionImport, members, parameters));
  210. }
  211. return imports;
  212. }
  213. private ImportDefinition TranslateImport(ReflectionImportDefinition reflectionImport, List<LazyMemberInfo> members, List<Lazy<ParameterInfo>> parameters)
  214. {
  215. bool isExportFactory = false;
  216. ContractBasedImportDefinition productImport = reflectionImport;
  217. IPartCreatorImportDefinition exportFactoryImportDefinition = reflectionImport as IPartCreatorImportDefinition;
  218. if (exportFactoryImportDefinition != null)
  219. {
  220. productImport = exportFactoryImportDefinition.ProductImportDefinition;
  221. isExportFactory = true;
  222. }
  223. string contractName = this.Translate(productImport.ContractName);
  224. string requiredTypeIdentity = this.Translate(productImport.RequiredTypeIdentity);
  225. IDictionary<string, object> metadata = this.TranslateImportMetadata(productImport);
  226. ReflectionMemberImportDefinition memberImport = reflectionImport as ReflectionMemberImportDefinition;
  227. ImportDefinition import = null;
  228. if (memberImport != null)
  229. {
  230. LazyMemberInfo lazyMember = memberImport.ImportingLazyMember;
  231. LazyMemberInfo importingMember = new LazyMemberInfo(lazyMember.MemberType, () => GetAccessors(lazyMember));
  232. if (isExportFactory)
  233. {
  234. import = new PartCreatorMemberImportDefinition(
  235. importingMember,
  236. ((ICompositionElement)memberImport).Origin,
  237. new ContractBasedImportDefinition(
  238. contractName,
  239. requiredTypeIdentity,
  240. productImport.RequiredMetadata,
  241. productImport.Cardinality,
  242. productImport.IsRecomposable,
  243. false,
  244. CreationPolicy.NonShared,
  245. metadata));
  246. }
  247. else
  248. {
  249. import = new ReflectionMemberImportDefinition(
  250. importingMember,
  251. contractName,
  252. requiredTypeIdentity,
  253. productImport.RequiredMetadata,
  254. productImport.Cardinality,
  255. productImport.IsRecomposable,
  256. false,
  257. productImport.RequiredCreationPolicy,
  258. metadata,
  259. ((ICompositionElement)memberImport).Origin);
  260. }
  261. members.Add(lazyMember);
  262. }
  263. else
  264. {
  265. ReflectionParameterImportDefinition parameterImport = reflectionImport as ReflectionParameterImportDefinition;
  266. Assumes.NotNull(parameterImport);
  267. Lazy<ParameterInfo> lazyParameter = parameterImport.ImportingLazyParameter;
  268. Lazy<ParameterInfo> parameter = new Lazy<ParameterInfo>(() => GetParameter(lazyParameter));
  269. if (isExportFactory)
  270. {
  271. import = new PartCreatorParameterImportDefinition(
  272. parameter,
  273. ((ICompositionElement)parameterImport).Origin,
  274. new ContractBasedImportDefinition(
  275. contractName,
  276. requiredTypeIdentity,
  277. productImport.RequiredMetadata,
  278. productImport.Cardinality,
  279. false,
  280. true,
  281. CreationPolicy.NonShared,
  282. metadata));
  283. }
  284. else
  285. {
  286. import = new ReflectionParameterImportDefinition(
  287. parameter,
  288. contractName,
  289. requiredTypeIdentity,
  290. productImport.RequiredMetadata,
  291. productImport.Cardinality,
  292. productImport.RequiredCreationPolicy,
  293. metadata,
  294. ((ICompositionElement)parameterImport).Origin);
  295. }
  296. parameters.Add(lazyParameter);
  297. }
  298. return import;
  299. }
  300. private List<ExportDefinition> PopulateExports(List<LazyMemberInfo> members)
  301. {
  302. List<ExportDefinition> exports = new List<ExportDefinition>();
  303. foreach (ExportDefinition originalExport in this._originalPartCreationInfo.GetExports())
  304. {
  305. ReflectionMemberExportDefinition reflectionExport = originalExport as ReflectionMemberExportDefinition;
  306. if (reflectionExport == null)
  307. {
  308. // we always ignore these
  309. continue;
  310. }
  311. exports.Add(this.TranslateExpot(reflectionExport, members));
  312. }
  313. return exports;
  314. }
  315. public ExportDefinition TranslateExpot(ReflectionMemberExportDefinition reflectionExport, List<LazyMemberInfo> members)
  316. {
  317. ExportDefinition export = null;
  318. LazyMemberInfo lazyMember = reflectionExport.ExportingLazyMember;
  319. var capturedLazyMember = lazyMember;
  320. var capturedReflectionExport = reflectionExport;
  321. string contractName = this.Translate(reflectionExport.ContractName, reflectionExport.Metadata.GetValue<int[]>(CompositionConstants.GenericExportParametersOrderMetadataName));
  322. LazyMemberInfo exportingMember = new LazyMemberInfo(capturedLazyMember.MemberType, () => GetAccessors(capturedLazyMember));
  323. Lazy<IDictionary<string, object>> lazyMetadata = new Lazy<IDictionary<string, object>>(() => this.TranslateExportMetadata(capturedReflectionExport));
  324. export = new ReflectionMemberExportDefinition(
  325. exportingMember,
  326. new LazyExportDefinition(contractName, lazyMetadata),
  327. ((ICompositionElement)reflectionExport).Origin);
  328. members.Add(capturedLazyMember);
  329. return export;
  330. }
  331. private string Translate(string originalValue, int[] genericParametersOrder)
  332. {
  333. if (genericParametersOrder != null)
  334. {
  335. string[] specializationIdentities = GenericServices.Reorder(this._specializationIdentities, genericParametersOrder);
  336. return string.Format(CultureInfo.InvariantCulture, originalValue, specializationIdentities);
  337. }
  338. else
  339. {
  340. return Translate(originalValue);
  341. }
  342. }
  343. private string Translate(string originalValue)
  344. {
  345. return string.Format(CultureInfo.InvariantCulture, originalValue, this._specializationIdentities);
  346. }
  347. private IDictionary<string, object> TranslateImportMetadata(ContractBasedImportDefinition originalImport)
  348. {
  349. int[] importParametersOrder = originalImport.Metadata.GetValue<int[]>(CompositionConstants.GenericImportParametersOrderMetadataName);
  350. if (importParametersOrder != null)
  351. {
  352. Dictionary<string, object> metadata = new Dictionary<string, object>(originalImport.Metadata, StringComparers.MetadataKeyNames);
  353. // Get the newly re-qualified name of the generic contract and the subset of applicable types from the specialization
  354. metadata[CompositionConstants.GenericContractMetadataName] = GenericServices.GetGenericName(originalImport.ContractName, importParametersOrder, this._specialization.Length);
  355. metadata[CompositionConstants.GenericParametersMetadataName] = GenericServices.Reorder(this._specialization, importParametersOrder);
  356. metadata.Remove(CompositionConstants.GenericImportParametersOrderMetadataName);
  357. return metadata.AsReadOnly();
  358. }
  359. else
  360. {
  361. return originalImport.Metadata;
  362. }
  363. }
  364. private IDictionary<string, object> TranslateExportMetadata(ReflectionMemberExportDefinition originalExport)
  365. {
  366. Dictionary<string, object> metadata = new Dictionary<string, object>(originalExport.Metadata, StringComparers.MetadataKeyNames);
  367. string exportTypeIdentity = originalExport.Metadata.GetValue<string>(CompositionConstants.ExportTypeIdentityMetadataName);
  368. if (!string.IsNullOrEmpty(exportTypeIdentity))
  369. {
  370. metadata[CompositionConstants.ExportTypeIdentityMetadataName] = this.Translate(exportTypeIdentity, originalExport.Metadata.GetValue<int[]>(CompositionConstants.GenericExportParametersOrderMetadataName));
  371. }
  372. metadata.Remove(CompositionConstants.GenericExportParametersOrderMetadataName);
  373. return metadata;
  374. }
  375. private void PopulateImportsAndExports()
  376. {
  377. if ((this._exports == null) || (this._imports == null))
  378. {
  379. List<LazyMemberInfo> members = new List<LazyMemberInfo>();
  380. List<Lazy<ParameterInfo>> parameters = new List<Lazy<ParameterInfo>>();
  381. // we are very careful to not call any 3rd party code in either of these
  382. var exports = this.PopulateExports(members);
  383. var imports = this.PopulateImports(members, parameters);
  384. Thread.MemoryBarrier();
  385. lock (this._lock)
  386. {
  387. if ((this._exports == null) || (this._imports == null))
  388. {
  389. this._members = members;
  390. if (parameters.Count > 0)
  391. {
  392. this._parameters = parameters;
  393. }
  394. this._exports = exports;
  395. this._imports = imports;
  396. }
  397. }
  398. }
  399. }
  400. public IEnumerable<ExportDefinition> GetExports()
  401. {
  402. this.PopulateImportsAndExports();
  403. return this._exports;
  404. }
  405. public IEnumerable<ImportDefinition> GetImports()
  406. {
  407. this.PopulateImportsAndExports();
  408. return this._imports;
  409. }
  410. public bool IsDisposalRequired
  411. {
  412. get { return this._originalPartCreationInfo.IsDisposalRequired; }
  413. }
  414. public string DisplayName
  415. {
  416. get { return this.Translate(this._originalPartCreationInfo.DisplayName); }
  417. }
  418. public ICompositionElement Origin
  419. {
  420. get { return this._originalPartCreationInfo.Origin; }
  421. }
  422. public override bool Equals(object obj)
  423. {
  424. GenericSpecializationPartCreationInfo that = obj as GenericSpecializationPartCreationInfo;
  425. if (that == null)
  426. {
  427. return false;
  428. }
  429. return (this._originalPartCreationInfo.Equals(that._originalPartCreationInfo)) &&
  430. (this._specialization.IsArrayEqual(that._specialization));
  431. }
  432. public override int GetHashCode()
  433. {
  434. return this._originalPartCreationInfo.GetHashCode();
  435. }
  436. public static bool CanSpecialize(IDictionary<string, object> partMetadata, Type[] specialization)
  437. {
  438. int partArity = partMetadata.GetValue<int>(CompositionConstants.GenericPartArityMetadataName);
  439. if (partArity != specialization.Length)
  440. {
  441. return false;
  442. }
  443. object[] genericParameterConstraints = partMetadata.GetValue<object[]>(CompositionConstants.GenericParameterConstraintsMetadataName);
  444. GenericParameterAttributes[] genericParameterAttributes = partMetadata.GetValue<GenericParameterAttributes[]>(CompositionConstants.GenericParameterAttributesMetadataName);
  445. // if no constraints and attributes been specifed, anything can be created
  446. if ((genericParameterConstraints == null) && (genericParameterAttributes == null))
  447. {
  448. return true;
  449. }
  450. if ((genericParameterConstraints != null) && (genericParameterConstraints.Length != partArity))
  451. {
  452. return false;
  453. }
  454. if ((genericParameterAttributes != null) && (genericParameterAttributes.Length != partArity))
  455. {
  456. return false;
  457. }
  458. for (int i = 0; i < partArity; i++)
  459. {
  460. if (!GenericServices.CanSpecialize(
  461. specialization[i],
  462. (genericParameterConstraints[i] as Type[]).CreateTypeSpecializations(specialization),
  463. genericParameterAttributes[i]))
  464. {
  465. return false;
  466. }
  467. }
  468. return true;
  469. }
  470. }
  471. }