/mcs/class/System.ComponentModel.Composition/src/ComponentModel/System/ComponentModel/Composition/ConstraintServices.cs

https://github.com/iainlane/mono · C# · 214 lines · 154 code · 38 blank · 22 comment · 13 complexity · d4af4eb6dcfe42351e8aaa1fc7347d93 MD5 · raw file

  1. // -----------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. // -----------------------------------------------------------------------
  4. using System;
  5. using System.Collections.Generic;
  6. using System.ComponentModel.Composition.Hosting;
  7. using System.ComponentModel.Composition.Primitives;
  8. using System.Linq;
  9. using System.Linq.Expressions;
  10. using System.Reflection;
  11. using Microsoft.Internal;
  12. namespace System.ComponentModel.Composition
  13. {
  14. internal static class ConstraintServices
  15. {
  16. // NOTE : these are here as Reflection member search is pretty expensive, and we want that to be done once.
  17. // Also, making these static would cause this class to fail loading if we rename members of ExportDefinition.
  18. private static readonly PropertyInfo _exportDefinitionContractNameProperty = typeof(ExportDefinition).GetProperty("ContractName");
  19. private static readonly PropertyInfo _exportDefinitionMetadataProperty = typeof(ExportDefinition).GetProperty("Metadata");
  20. private static readonly MethodInfo _metadataContainsKeyMethod = typeof(IDictionary<string, object>).GetMethod("ContainsKey");
  21. private static readonly MethodInfo _metadataItemMethod = typeof(IDictionary<string, object>).GetMethod("get_Item");
  22. private static readonly MethodInfo _metadataEqualsMethod = typeof(object).GetMethod("Equals", new Type[] { typeof(object) });
  23. private static readonly MethodInfo _typeIsInstanceOfTypeMethod = typeof(Type).GetMethod("IsInstanceOfType");
  24. public static Expression<Func<ExportDefinition, bool>> CreateConstraint(IEnumerable<KeyValuePair<string, Type>> requiredMetadata)
  25. {
  26. ParameterExpression parameter = Expression.Parameter(typeof(ExportDefinition), "exportDefinition");
  27. Expression metadataConstraintBody = null;
  28. if (requiredMetadata != null)
  29. {
  30. metadataConstraintBody = ConstraintServices.CreateMetadataConstraintBody(requiredMetadata, parameter);
  31. }
  32. if (metadataConstraintBody != null)
  33. {
  34. return Expression.Lambda<Func<ExportDefinition, bool>>(metadataConstraintBody, parameter);
  35. }
  36. return null;
  37. }
  38. public static Expression<Func<ExportDefinition, bool>> CreateConstraint(string contractName, string requiredTypeIdentity, IEnumerable<KeyValuePair<string, Type>> requiredMetadata, CreationPolicy requiredCreationPolicy)
  39. {
  40. ParameterExpression parameter = Expression.Parameter(typeof(ExportDefinition), "exportDefinition");
  41. Expression constraintBody = ConstraintServices.CreateContractConstraintBody(contractName, parameter);
  42. if (!string.IsNullOrEmpty(requiredTypeIdentity))
  43. {
  44. Expression typeIdentityConstraintBody = ConstraintServices.CreateTypeIdentityContraint(requiredTypeIdentity, parameter);
  45. constraintBody = Expression.AndAlso(constraintBody, typeIdentityConstraintBody);
  46. }
  47. if (requiredMetadata != null)
  48. {
  49. Expression metadataConstraintBody = ConstraintServices.CreateMetadataConstraintBody(requiredMetadata, parameter);
  50. if (metadataConstraintBody != null)
  51. {
  52. constraintBody = Expression.AndAlso(constraintBody, metadataConstraintBody);
  53. }
  54. }
  55. if (requiredCreationPolicy != CreationPolicy.Any)
  56. {
  57. Expression policyConstraintBody = ConstraintServices.CreateCreationPolicyContraint(requiredCreationPolicy, parameter);
  58. constraintBody = Expression.AndAlso(constraintBody, policyConstraintBody);
  59. }
  60. Expression<Func<ExportDefinition, bool>> constraint = Expression.Lambda<Func<ExportDefinition, bool>>(constraintBody, parameter);
  61. return constraint;
  62. }
  63. private static Expression CreateContractConstraintBody(string contractName, ParameterExpression parameter)
  64. {
  65. Assumes.NotNull(parameter);
  66. // export.ContractName=<contract>;
  67. return Expression.Equal(
  68. Expression.Property(parameter, ConstraintServices._exportDefinitionContractNameProperty),
  69. Expression.Constant(contractName ?? string.Empty, typeof(string)));
  70. }
  71. private static Expression CreateMetadataConstraintBody(IEnumerable<KeyValuePair<string, Type>> requiredMetadata, ParameterExpression parameter)
  72. {
  73. Assumes.NotNull(requiredMetadata);
  74. Assumes.NotNull(parameter);
  75. Expression body = null;
  76. foreach (KeyValuePair<string, Type> requiredMetadataItem in requiredMetadata)
  77. {
  78. // export.Metadata.ContainsKey(<metadataItem>)
  79. Expression metadataItemExpression = CreateMetadataContainsKeyExpression(parameter, requiredMetadataItem.Key);
  80. body = (body != null) ? Expression.AndAlso(body, metadataItemExpression) : metadataItemExpression;
  81. body = Expression.AndAlso(body, CreateMetadataOfTypeExpression(parameter, requiredMetadataItem.Key, requiredMetadataItem.Value));
  82. }
  83. return body;
  84. }
  85. private static Expression CreateCreationPolicyContraint(CreationPolicy policy, ParameterExpression parameter)
  86. {
  87. Assumes.IsTrue(policy != CreationPolicy.Any);
  88. Assumes.NotNull(parameter);
  89. // !definition.Metadata.ContainsKey(CompositionConstants.PartCreationPolicyMetadataName) ||
  90. // CreationPolicy.Any.Equals(definition.Metadata[CompositionConstants.PartCreationPolicyMetadataName]) ||
  91. // policy.Equals(definition.Metadata[CompositionConstants.PartCreationPolicyMetadataName]);
  92. return Expression.MakeBinary(ExpressionType.OrElse,
  93. Expression.MakeBinary(ExpressionType.OrElse,
  94. Expression.Not(CreateMetadataContainsKeyExpression(parameter, CompositionConstants.PartCreationPolicyMetadataName)),
  95. CreateMetadataValueEqualsExpression(parameter, CreationPolicy.Any, CompositionConstants.PartCreationPolicyMetadataName)),
  96. CreateMetadataValueEqualsExpression(parameter, policy, CompositionConstants.PartCreationPolicyMetadataName));
  97. }
  98. private static Expression CreateTypeIdentityContraint(string requiredTypeIdentity, ParameterExpression parameter)
  99. {
  100. Assumes.NotNull(requiredTypeIdentity);
  101. Assumes.NotNull(parameter);
  102. // definition.Metadata.ContainsKey(CompositionServices.ExportTypeIdentity) &&
  103. // requiredTypeIdentity.Equals(definition.Metadata[CompositionConstants.ExportTypeIdentityMetadataName]);
  104. return Expression.MakeBinary(ExpressionType.AndAlso,
  105. CreateMetadataContainsKeyExpression(parameter, CompositionConstants.ExportTypeIdentityMetadataName),
  106. CreateMetadataValueEqualsExpression(parameter, requiredTypeIdentity, CompositionConstants.ExportTypeIdentityMetadataName));
  107. }
  108. private static Expression CreateMetadataContainsKeyExpression(ParameterExpression parameter, string constantKey)
  109. {
  110. Assumes.NotNull(parameter, constantKey);
  111. // definition.Metadata.ContainsKey(constantKey)
  112. return Expression.Call(
  113. Expression.Property(parameter, ConstraintServices._exportDefinitionMetadataProperty),
  114. ConstraintServices._metadataContainsKeyMethod,
  115. Expression.Constant(constantKey));
  116. }
  117. private static Expression CreateMetadataOfTypeExpression(ParameterExpression parameter, string constantKey, Type constantType)
  118. {
  119. Assumes.NotNull(parameter, constantKey);
  120. Assumes.NotNull(parameter, constantType);
  121. // constantType.IsInstanceOfType(definition.Metadata[constantKey])
  122. return Expression.Call(
  123. Expression.Constant(constantType, typeof(Type)),
  124. ConstraintServices._typeIsInstanceOfTypeMethod,
  125. Expression.Call(
  126. Expression.Property(parameter, ConstraintServices._exportDefinitionMetadataProperty),
  127. ConstraintServices._metadataItemMethod,
  128. Expression.Constant(constantKey))
  129. );
  130. }
  131. private static Expression CreateMetadataValueEqualsExpression(ParameterExpression parameter, object constantValue, string metadataName)
  132. {
  133. Assumes.NotNull(parameter, constantValue);
  134. // constantValue.Equals(definition.Metadata[CompositionServices.PartCreationPolicyMetadataName])
  135. return Expression.Call(
  136. Expression.Constant(constantValue),
  137. ConstraintServices._metadataEqualsMethod,
  138. Expression.Call(
  139. Expression.Property(parameter, ConstraintServices._exportDefinitionMetadataProperty),
  140. ConstraintServices._metadataItemMethod,
  141. Expression.Constant(metadataName)));
  142. }
  143. public static Expression<Func<ExportDefinition, bool>> CreatePartCreatorConstraint(Expression<Func<ExportDefinition, bool>> baseConstraint, ImportDefinition productImportDefinition)
  144. {
  145. ParameterExpression exportDefinitionParameter = baseConstraint.Parameters[0];
  146. // exportDefinition.Metadata
  147. Expression metadataExpression = Expression.Property(exportDefinitionParameter, ConstraintServices._exportDefinitionMetadataProperty);
  148. // exportDefinition.Metadata.ContainsKey("ProductDefinition")
  149. Expression containsProductExpression = Expression.Call(
  150. metadataExpression,
  151. ConstraintServices._metadataContainsKeyMethod,
  152. Expression.Constant(CompositionConstants.ProductDefinitionMetadataName));
  153. // exportDefinition.Metadata["ProductDefinition"]
  154. Expression productExportDefinitionExpression = Expression.Call(
  155. metadataExpression,
  156. ConstraintServices._metadataItemMethod,
  157. Expression.Constant(CompositionConstants.ProductDefinitionMetadataName));
  158. // ProductImportDefinition.Contraint((ExportDefinition)exportDefinition.Metadata["ProductDefinition"])
  159. Expression productMatchExpression =
  160. Expression.Invoke(productImportDefinition.Constraint,
  161. Expression.Convert(productExportDefinitionExpression, typeof(ExportDefinition)));
  162. // baseContraint(exportDefinition) &&
  163. // exportDefinition.Metadata.ContainsKey("ProductDefinition") &&
  164. // ProductImportDefinition.Contraint((ExportDefinition)exportDefinition.Metadata["ProductDefinition"])
  165. Expression<Func<ExportDefinition, bool>> constraint =
  166. Expression.Lambda<Func<ExportDefinition, bool>>(
  167. Expression.AndAlso(
  168. baseConstraint.Body,
  169. Expression.AndAlso(
  170. containsProductExpression,
  171. productMatchExpression)),
  172. exportDefinitionParameter);
  173. return constraint;
  174. }
  175. }
  176. }