--- /dev/null
+// -----------------------------------------------------------------------\r
+// Copyright (c) Microsoft Corporation. All rights reserved.\r
+// -----------------------------------------------------------------------\r
+using System;\r
+using System.Collections.Generic;\r
+using System.ComponentModel.Composition.Primitives;\r
+using System.Globalization;\r
+using System.Linq;\r
+using Microsoft.Internal;\r
+\r
+namespace System.ComponentModel.Composition.Hosting\r
+{\r
+ /// <summary>\r
+ /// Defines the <see langword="abstract"/> base class for export providers, which provide\r
+ /// methods for retrieving <see cref="Export"/> objects.\r
+ /// </summary>\r
+ public abstract partial class ExportProvider\r
+ {\r
+ /// <summary>\r
+ /// Initializes a new instance of the <see cref="ExportProvider"/> class.\r
+ /// </summary>\r
+ protected ExportProvider()\r
+ {\r
+ }\r
+\r
+ /// <summary>\r
+ /// Occurs when the exports in the <see cref="ExportProvider"/> have changed.\r
+ /// </summary>\r
+ public event EventHandler<ExportsChangeEventArgs> ExportsChanged;\r
+\r
+ /// <summary>\r
+ /// Occurs when the exports in the <see cref="ExportProvider"/> are changing.\r
+ /// </summary>\r
+ public event EventHandler<ExportsChangeEventArgs> ExportsChanging;\r
+\r
+ /// <summary>\r
+ /// Returns all exports that match the conditions of the specified import.\r
+ /// </summary>\r
+ /// <param name="definition">\r
+ /// The <see cref="ImportDefinition"/> that defines the conditions of the \r
+ /// <see cref="Export"/> objects to get.\r
+ /// </param>\r
+ /// <result>\r
+ /// An <see cref="IEnumerable{T}"/> of <see cref="Export"/> objects that match \r
+ /// the conditions defined by <see cref="ImportDefinition"/>, if found; otherwise, an \r
+ /// empty <see cref="IEnumerable{T}"/>.\r
+ /// </result>\r
+ /// <exception cref="ArgumentNullException">\r
+ /// <paramref name="definition"/> is <see langword="null"/>.\r
+ /// </exception>\r
+ /// <exception cref="ImportCardinalityMismatchException">\r
+ /// <para>\r
+ /// <see cref="ImportDefinition.Cardinality"/> is <see cref="ImportCardinality.ExactlyOne"/> and \r
+ /// there are zero <see cref="Export"/> objects that match the conditions of the specified \r
+ /// <see cref="ImportDefinition"/>.\r
+ /// </para>\r
+ /// -or-\r
+ /// <para>\r
+ /// <see cref="ImportDefinition.Cardinality"/> is <see cref="ImportCardinality.ZeroOrOne"/> or \r
+ /// <see cref="ImportCardinality.ExactlyOne"/> and there are more than one <see cref="Export"/> \r
+ /// objects that match the conditions of the specified <see cref="ImportDefinition"/>.\r
+ /// </para>\r
+ /// </exception>\r
+ public IEnumerable<Export> GetExports(ImportDefinition definition)\r
+ {\r
+ return GetExports(definition, null);\r
+ }\r
+\r
+ /// <summary>\r
+ /// Returns all exports that match the conditions of the specified import.\r
+ /// </summary>\r
+ /// <param name="definition">\r
+ /// The <see cref="ImportDefinition"/> that defines the conditions of the \r
+ /// <see cref="Export"/> objects to get.\r
+ /// </param>\r
+ /// <result>\r
+ /// An <see cref="IEnumerable{T}"/> of <see cref="Export"/> objects that match \r
+ /// the conditions defined by <see cref="ImportDefinition"/>, if found; otherwise, an \r
+ /// empty <see cref="IEnumerable{T}"/>.\r
+ /// </result>\r
+ /// <exception cref="ArgumentNullException">\r
+ /// <paramref name="definition"/> is <see langword="null"/>.\r
+ /// </exception>\r
+ /// <exception cref="ImportCardinalityMismatchException">\r
+ /// <para>\r
+ /// <see cref="ImportDefinition.Cardinality"/> is <see cref="ImportCardinality.ExactlyOne"/> and \r
+ /// there are zero <see cref="Export"/> objects that match the conditions of the specified \r
+ /// <see cref="ImportDefinition"/>.\r
+ /// </para>\r
+ /// -or-\r
+ /// <para>\r
+ /// <see cref="ImportDefinition.Cardinality"/> is <see cref="ImportCardinality.ZeroOrOne"/> or \r
+ /// <see cref="ImportCardinality.ExactlyOne"/> and there are more than one <see cref="Export"/> \r
+ /// objects that match the conditions of the specified <see cref="ImportDefinition"/>.\r
+ /// </para>\r
+ /// </exception>\r
+ public IEnumerable<Export> GetExports(ImportDefinition definition, AtomicComposition atomicComposition)\r
+ {\r
+ Requires.NotNull(definition, "definition");\r
+\r
+ IEnumerable<Export> exports;\r
+ ExportCardinalityCheckResult result = this.TryGetExportsCore(definition, atomicComposition, out exports);\r
+ switch(result)\r
+ {\r
+ case ExportCardinalityCheckResult.Match:\r
+ return exports;\r
+ case ExportCardinalityCheckResult.NoExports:\r
+ throw new ImportCardinalityMismatchException(string.Format(CultureInfo.CurrentCulture, Strings.CardinalityMismatch_NoExports, definition.Constraint.Body.ToString()));\r
+ default:\r
+ Assumes.IsTrue(result == ExportCardinalityCheckResult.TooManyExports);\r
+ throw new ImportCardinalityMismatchException(string.Format(CultureInfo.CurrentCulture, Strings.CardinalityMismatch_TooManyExports, definition.Constraint.Body.ToString()));\r
+ }\r
+ }\r
+\r
+ /// <summary>\r
+ /// Returns all exports that match the conditions of the specified import.\r
+ /// </summary>\r
+ /// <param name="definition">\r
+ /// The <see cref="ImportDefinition"/> that defines the conditions of the \r
+ /// <see cref="Export"/> objects to get.\r
+ /// </param>\r
+ /// <param name="exports">\r
+ /// When this method returns, contains an <see cref="IEnumerable{T}"/> of <see cref="Export"/> \r
+ /// objects that match the conditions defined by <see cref="ImportDefinition"/>, if found; \r
+ /// otherwise, an empty <see cref="IEnumerable{T}"/>.\r
+ /// </param>\r
+ /// <returns>\r
+ /// <see langword="true"/> if <see cref="ImportDefinition.Cardinality"/> is \r
+ /// <see cref="ImportCardinality.ZeroOrOne"/> or <see cref="ImportCardinality.ZeroOrMore"/> and \r
+ /// there are zero <see cref="Export"/> objects that match the conditions of the specified \r
+ /// <see cref="ImportDefinition"/>. <see langword="true"/> if \r
+ /// <see cref="ImportDefinition.Cardinality"/> is <see cref="ImportCardinality.ZeroOrOne"/> or \r
+ /// <see cref="ImportCardinality.ExactlyOne"/> and there is exactly one <see cref="Export"/> \r
+ /// that matches the conditions of the specified <see cref="ImportDefinition"/>; otherwise, \r
+ /// <see langword="false"/>.\r
+ /// </returns>\r
+ /// <exception cref="ArgumentNullException">\r
+ /// <paramref name="definition"/> is <see langword="null"/>.\r
+ /// </exception>\r
+ public bool TryGetExports(ImportDefinition definition, AtomicComposition atomicComposition, out IEnumerable<Export> exports)\r
+ {\r
+ Requires.NotNull(definition, "definition");\r
+\r
+ exports = null;\r
+ ExportCardinalityCheckResult result = this.TryGetExportsCore(definition, atomicComposition, out exports);\r
+ return (result == ExportCardinalityCheckResult.Match);\r
+ }\r
+ \r
+ /// <summary>\r
+ /// Returns all exports that match the constraint defined by the specified definition.\r
+ /// </summary>\r
+ /// <param name="definition">\r
+ /// The <see cref="ImportDefinition"/> that defines the conditions of the \r
+ /// <see cref="Export"/> objects to return.\r
+ /// </param>\r
+ /// <result>\r
+ /// An <see cref="IEnumerable{T}"/> of <see cref="Export"/> objects that match \r
+ /// the conditions defined by <see cref="ImportDefinition"/>, if found; otherwise, an \r
+ /// empty <see cref="IEnumerable{T}"/>.\r
+ /// </result>\r
+ /// <remarks>\r
+ /// <note type="inheritinfo">\r
+ /// Overriders of this method should not treat cardinality-related mismatches \r
+ /// as errors, and should not throw exceptions in those cases. For instance,\r
+ /// if <see cref="ImportDefinition.Cardinality"/> is <see cref="ImportCardinality.ExactlyOne"/> \r
+ /// and there are zero <see cref="Export"/> objects that match the conditions of the \r
+ /// specified <see cref="ImportDefinition"/>, an <see cref="IEnumerable{T}"/> should be returned.\r
+ /// </note>\r
+ /// </remarks>\r
+ protected abstract IEnumerable<Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition);\r
+\r
+ /// <summary>\r
+ /// Raises the <see cref="ExportsChanged"/> event.\r
+ /// </summary>\r
+ /// <param name="e">\r
+ /// An <see cref="ExportsChangeEventArgs"/> containing the data for the event.\r
+ /// </param>\r
+ protected virtual void OnExportsChanged(ExportsChangeEventArgs e)\r
+ {\r
+ EventHandler<ExportsChangeEventArgs> changedEvent = this.ExportsChanged;\r
+ if (changedEvent != null)\r
+ {\r
+ CompositionResult result = CompositionServices.TryFire(changedEvent, this, e);\r
+ result.ThrowOnErrors(e.AtomicComposition);\r
+ }\r
+ }\r
+\r
+ /// <summary>\r
+ /// Raises the <see cref="ExportsChanging"/> event.\r
+ /// </summary>\r
+ /// <param name="e">\r
+ /// An <see cref="ExportsChangeEventArgs"/> containing the data for the event.\r
+ /// </param>\r
+ protected virtual void OnExportsChanging(ExportsChangeEventArgs e)\r
+ {\r
+ EventHandler<ExportsChangeEventArgs> changingEvent = this.ExportsChanging;\r
+ if (changingEvent != null)\r
+ {\r
+ CompositionResult result = CompositionServices.TryFire(changingEvent, this, e);\r
+ result.ThrowOnErrors(e.AtomicComposition);\r
+ }\r
+ }\r
+\r
+ private ExportCardinalityCheckResult TryGetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition, out IEnumerable<Export> exports)\r
+ {\r
+ Assumes.NotNull(definition);\r
+\r
+ exports = this.GetExportsCore(definition, atomicComposition);\r
+\r
+ if (exports == null)\r
+ {\r
+ exports = Enumerable.Empty<Export>();\r
+ }\r
+\r
+ var checkResult = ExportServices.CheckCardinality(definition, exports);\r
+\r
+ // Export providers treat >1 match as zero for cardinality 0-1 imports\r
+ // If this policy is moved we need to revisit the assumption that the\r
+ // ImportEngine made during previewing the only required imports to \r
+ // now also preview optional imports.\r
+ if (checkResult == ExportCardinalityCheckResult.TooManyExports &&\r
+ definition.Cardinality == ImportCardinality.ZeroOrOne)\r
+ {\r
+ checkResult = ExportCardinalityCheckResult.Match;\r
+ exports = Enumerable.Empty<Export>();\r
+ }\r
+\r
+ return checkResult;\r
+ }\r
+ }\r
+}\r