/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ExportProvider.cs

https://github.com/iainlane/mono · C# · 235 lines · 83 code · 18 blank · 134 comment · 12 complexity · d893d0a0c9c18d358f90e788a8d69da2 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.Primitives;
  7. using System.Diagnostics.Contracts;
  8. using System.Globalization;
  9. using System.Linq;
  10. using Microsoft.Internal;
  11. namespace System.ComponentModel.Composition.Hosting
  12. {
  13. /// <summary>
  14. /// Defines the <see langword="abstract"/> base class for export providers, which provide
  15. /// methods for retrieving <see cref="Export"/> objects.
  16. /// </summary>
  17. public abstract partial class ExportProvider
  18. {
  19. private static readonly Export[] EmptyExports = new Export[] { };
  20. /// <summary>
  21. /// Initializes a new instance of the <see cref="ExportProvider"/> class.
  22. /// </summary>
  23. protected ExportProvider()
  24. {
  25. }
  26. /// <summary>
  27. /// Occurs when the exports in the <see cref="ExportProvider"/> have changed.
  28. /// </summary>
  29. public event EventHandler<ExportsChangeEventArgs> ExportsChanged;
  30. /// <summary>
  31. /// Occurs when the exports in the <see cref="ExportProvider"/> are changing.
  32. /// </summary>
  33. public event EventHandler<ExportsChangeEventArgs> ExportsChanging;
  34. /// <summary>
  35. /// Returns all exports that match the conditions of the specified import.
  36. /// </summary>
  37. /// <param name="definition">
  38. /// The <see cref="ImportDefinition"/> that defines the conditions of the
  39. /// <see cref="Export"/> objects to get.
  40. /// </param>
  41. /// <result>
  42. /// An <see cref="IEnumerable{T}"/> of <see cref="Export"/> objects that match
  43. /// the conditions defined by <see cref="ImportDefinition"/>, if found; otherwise, an
  44. /// empty <see cref="IEnumerable{T}"/>.
  45. /// </result>
  46. /// <exception cref="ArgumentNullException">
  47. /// <paramref name="definition"/> is <see langword="null"/>.
  48. /// </exception>
  49. /// <exception cref="ImportCardinalityMismatchException">
  50. /// <para>
  51. /// <see cref="ImportDefinition.Cardinality"/> is <see cref="ImportCardinality.ExactlyOne"/> and
  52. /// there are zero <see cref="Export"/> objects that match the conditions of the specified
  53. /// <see cref="ImportDefinition"/>.
  54. /// </para>
  55. /// -or-
  56. /// <para>
  57. /// <see cref="ImportDefinition.Cardinality"/> is <see cref="ImportCardinality.ZeroOrOne"/> or
  58. /// <see cref="ImportCardinality.ExactlyOne"/> and there are more than one <see cref="Export"/>
  59. /// objects that match the conditions of the specified <see cref="ImportDefinition"/>.
  60. /// </para>
  61. /// </exception>
  62. public IEnumerable<Export> GetExports(ImportDefinition definition)
  63. {
  64. return GetExports(definition, null);
  65. }
  66. /// <summary>
  67. /// Returns all exports that match the conditions of the specified import.
  68. /// </summary>
  69. /// <param name="definition">
  70. /// The <see cref="ImportDefinition"/> that defines the conditions of the
  71. /// <see cref="Export"/> objects to get.
  72. /// </param>
  73. /// <result>
  74. /// An <see cref="IEnumerable{T}"/> of <see cref="Export"/> objects that match
  75. /// the conditions defined by <see cref="ImportDefinition"/>, if found; otherwise, an
  76. /// empty <see cref="IEnumerable{T}"/>.
  77. /// </result>
  78. /// <exception cref="ArgumentNullException">
  79. /// <paramref name="definition"/> is <see langword="null"/>.
  80. /// </exception>
  81. /// <exception cref="ImportCardinalityMismatchException">
  82. /// <para>
  83. /// <see cref="ImportDefinition.Cardinality"/> is <see cref="ImportCardinality.ExactlyOne"/> and
  84. /// there are zero <see cref="Export"/> objects that match the conditions of the specified
  85. /// <see cref="ImportDefinition"/>.
  86. /// </para>
  87. /// -or-
  88. /// <para>
  89. /// <see cref="ImportDefinition.Cardinality"/> is <see cref="ImportCardinality.ZeroOrOne"/> or
  90. /// <see cref="ImportCardinality.ExactlyOne"/> and there are more than one <see cref="Export"/>
  91. /// objects that match the conditions of the specified <see cref="ImportDefinition"/>.
  92. /// </para>
  93. /// </exception>
  94. public IEnumerable<Export> GetExports(ImportDefinition definition, AtomicComposition atomicComposition)
  95. {
  96. Requires.NotNull(definition, "definition");
  97. Contract.Ensures(Contract.Result<IEnumerable<Export>>() != null);
  98. IEnumerable<Export> exports;
  99. ExportCardinalityCheckResult result = this.TryGetExportsCore(definition, atomicComposition, out exports);
  100. switch(result)
  101. {
  102. case ExportCardinalityCheckResult.Match:
  103. return exports;
  104. case ExportCardinalityCheckResult.NoExports:
  105. throw new ImportCardinalityMismatchException(string.Format(CultureInfo.CurrentCulture, Strings.CardinalityMismatch_NoExports, definition.ToString()));
  106. default:
  107. Assumes.IsTrue(result == ExportCardinalityCheckResult.TooManyExports);
  108. throw new ImportCardinalityMismatchException(string.Format(CultureInfo.CurrentCulture, Strings.CardinalityMismatch_TooManyExports, definition.ToString()));
  109. }
  110. }
  111. /// <summary>
  112. /// Returns all exports that match the conditions of the specified import.
  113. /// </summary>
  114. /// <param name="definition">
  115. /// The <see cref="ImportDefinition"/> that defines the conditions of the
  116. /// <see cref="Export"/> objects to get.
  117. /// </param>
  118. /// <param name="exports">
  119. /// When this method returns, contains an <see cref="IEnumerable{T}"/> of <see cref="Export"/>
  120. /// objects that match the conditions defined by <see cref="ImportDefinition"/>, if found;
  121. /// otherwise, an empty <see cref="IEnumerable{T}"/>.
  122. /// </param>
  123. /// <returns>
  124. /// <see langword="true"/> if <see cref="ImportDefinition.Cardinality"/> is
  125. /// <see cref="ImportCardinality.ZeroOrOne"/> or <see cref="ImportCardinality.ZeroOrMore"/> and
  126. /// there are zero <see cref="Export"/> objects that match the conditions of the specified
  127. /// <see cref="ImportDefinition"/>. <see langword="true"/> if
  128. /// <see cref="ImportDefinition.Cardinality"/> is <see cref="ImportCardinality.ZeroOrOne"/> or
  129. /// <see cref="ImportCardinality.ExactlyOne"/> and there is exactly one <see cref="Export"/>
  130. /// that matches the conditions of the specified <see cref="ImportDefinition"/>; otherwise,
  131. /// <see langword="false"/>.
  132. /// </returns>
  133. /// <exception cref="ArgumentNullException">
  134. /// <paramref name="definition"/> is <see langword="null"/>.
  135. /// </exception>
  136. public bool TryGetExports(ImportDefinition definition, AtomicComposition atomicComposition, out IEnumerable<Export> exports)
  137. {
  138. Requires.NotNull(definition, "definition");
  139. exports = null;
  140. ExportCardinalityCheckResult result = this.TryGetExportsCore(definition, atomicComposition, out exports);
  141. return (result == ExportCardinalityCheckResult.Match);
  142. }
  143. /// <summary>
  144. /// Returns all exports that match the constraint defined by the specified definition.
  145. /// </summary>
  146. /// <param name="definition">
  147. /// The <see cref="ImportDefinition"/> that defines the conditions of the
  148. /// <see cref="Export"/> objects to return.
  149. /// </param>
  150. /// <result>
  151. /// An <see cref="IEnumerable{T}"/> of <see cref="Export"/> objects that match
  152. /// the conditions defined by <see cref="ImportDefinition"/>, if found; otherwise, an
  153. /// empty <see cref="IEnumerable{T}"/>.
  154. /// </result>
  155. /// <remarks>
  156. /// <note type="inheritinfo">
  157. /// Overriders of this method should not treat cardinality-related mismatches
  158. /// as errors, and should not throw exceptions in those cases. For instance,
  159. /// if <see cref="ImportDefinition.Cardinality"/> is <see cref="ImportCardinality.ExactlyOne"/>
  160. /// and there are zero <see cref="Export"/> objects that match the conditions of the
  161. /// specified <see cref="ImportDefinition"/>, an <see cref="IEnumerable{T}"/> should be returned.
  162. /// </note>
  163. /// </remarks>
  164. protected abstract IEnumerable<Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition);
  165. /// <summary>
  166. /// Raises the <see cref="ExportsChanged"/> event.
  167. /// </summary>
  168. /// <param name="e">
  169. /// An <see cref="ExportsChangeEventArgs"/> containing the data for the event.
  170. /// </param>
  171. protected virtual void OnExportsChanged(ExportsChangeEventArgs e)
  172. {
  173. EventHandler<ExportsChangeEventArgs> changedEvent = this.ExportsChanged;
  174. if (changedEvent != null)
  175. {
  176. CompositionResult result = CompositionServices.TryFire(changedEvent, this, e);
  177. result.ThrowOnErrors(e.AtomicComposition);
  178. }
  179. }
  180. /// <summary>
  181. /// Raises the <see cref="ExportsChanging"/> event.
  182. /// </summary>
  183. /// <param name="e">
  184. /// An <see cref="ExportsChangeEventArgs"/> containing the data for the event.
  185. /// </param>
  186. protected virtual void OnExportsChanging(ExportsChangeEventArgs e)
  187. {
  188. EventHandler<ExportsChangeEventArgs> changingEvent = this.ExportsChanging;
  189. if (changingEvent != null)
  190. {
  191. CompositionResult result = CompositionServices.TryFire(changingEvent, this, e);
  192. result.ThrowOnErrors(e.AtomicComposition);
  193. }
  194. }
  195. private ExportCardinalityCheckResult TryGetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition, out IEnumerable<Export> exports)
  196. {
  197. Assumes.NotNull(definition);
  198. exports = this.GetExportsCore(definition, atomicComposition);
  199. var checkResult = ExportServices.CheckCardinality(definition, exports);
  200. // Export providers treat >1 match as zero for cardinality 0-1 imports
  201. // If this policy is moved we need to revisit the assumption that the
  202. // ImportEngine made during previewing the only required imports to
  203. // now also preview optional imports.
  204. if (checkResult == ExportCardinalityCheckResult.TooManyExports &&
  205. definition.Cardinality == ImportCardinality.ZeroOrOne)
  206. {
  207. checkResult = ExportCardinalityCheckResult.Match;
  208. exports = null;
  209. }
  210. if (exports == null)
  211. {
  212. exports = EmptyExports;
  213. }
  214. return checkResult;
  215. }
  216. }
  217. }