Add MEF for .NET 4
[mono.git] / mcs / class / System.ComponentModel.Composition / src / ComponentModel / System / ComponentModel / Composition / Hosting / ExportProvider.cs
diff --git a/mcs/class/System.ComponentModel.Composition/src/ComponentModel/System/ComponentModel/Composition/Hosting/ExportProvider.cs b/mcs/class/System.ComponentModel.Composition/src/ComponentModel/System/ComponentModel/Composition/Hosting/ExportProvider.cs
new file mode 100644 (file)
index 0000000..015996e
--- /dev/null
@@ -0,0 +1,231 @@
+// -----------------------------------------------------------------------\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