Add 4.5 compatible MEF
[mono.git] / mcs / class / System.ComponentModel.Composition.4.5 / src / ComponentModel / System / ComponentModel / Composition / Hosting / FilteredCatalog.DependentsTraversal.cs
diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/FilteredCatalog.DependentsTraversal.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/FilteredCatalog.DependentsTraversal.cs
new file mode 100644 (file)
index 0000000..e4593f1
--- /dev/null
@@ -0,0 +1,103 @@
+// -----------------------------------------------------------------------
+// Copyright (c) Microsoft Corporation.  All rights reserved.
+// -----------------------------------------------------------------------
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.Composition.Primitives;
+using System.ComponentModel.Composition.ReflectionModel;
+using System.Linq;
+using Microsoft.Internal;
+
+namespace System.ComponentModel.Composition.Hosting
+{
+    public partial class FilteredCatalog
+    {
+        /// <summary>
+        /// Implementation of IComposablePartTraversal supporting the Dependents traveral pattern.
+        /// The implementation is optimized for a situation when the traversal is expected to be rather short-lived - that is,
+        /// if the chains of dependecies are rather small. To achieve that we do a very minimal structure prep upfront - merely creating a contract-based
+        /// index of imports - and the verify the full match of imports during the traversal. Given that most parts have a very few imports this should perform well.
+        /// </summary>
+        internal class DependentsTraversal : IComposablePartCatalogTraversal
+        {
+            private IEnumerable<ComposablePartDefinition> _parts;
+            private Func<ImportDefinition, bool> _importFilter;
+            private Dictionary<string, List<ComposablePartDefinition>> _importersIndex;
+
+            public DependentsTraversal(FilteredCatalog catalog, Func<ImportDefinition, bool> importFilter)
+            {
+                Assumes.NotNull(catalog);
+                Assumes.NotNull(importFilter);
+
+                this._parts = catalog._innerCatalog;
+                this._importFilter = importFilter;
+            }
+
+            public void Initialize()
+            {
+                this.BuildImportersIndex();
+            }
+
+            private void BuildImportersIndex()
+            {
+                this._importersIndex = new Dictionary<string, List<ComposablePartDefinition>>();
+                foreach (ComposablePartDefinition part in this._parts)
+                {
+                    foreach (var import in part.ImportDefinitions)
+                    {
+                        foreach (var contractName in import.GetCandidateContractNames(part))
+                        {
+                            this.AddToImportersIndex(contractName, part);
+                        }
+                    }
+                }
+            }
+
+
+            private void AddToImportersIndex(string contractName, ComposablePartDefinition part)
+            {
+                List<ComposablePartDefinition> parts = null;
+                if (!this._importersIndex.TryGetValue(contractName, out parts))
+                {
+                    parts = new List<ComposablePartDefinition>();
+                    this._importersIndex.Add(contractName, parts);
+                }
+                parts.Add(part);
+            }
+
+            public bool TryTraverse(ComposablePartDefinition part, out IEnumerable<ComposablePartDefinition> reachableParts)
+            {
+                reachableParts = null;
+                List<ComposablePartDefinition> reachablePartList = null;
+
+                // Go through all part exports
+                foreach (ExportDefinition export in part.ExportDefinitions)
+                {
+                    // Find all parts that we know will import each export
+                    List<ComposablePartDefinition> candidateReachableParts = null;
+                    if (this._importersIndex.TryGetValue(export.ContractName, out candidateReachableParts))
+                    {
+                        // find if they actually match
+                        foreach (var candidateReachablePart in candidateReachableParts)
+                        {
+                            foreach (ImportDefinition import in candidateReachablePart.ImportDefinitions.Where(this._importFilter))
+                            {
+                                if (import.IsImportDependentOnPart(part, export, part.IsGeneric() != candidateReachablePart.IsGeneric()))
+                                {
+                                    if (reachablePartList == null)
+                                    {
+                                        reachablePartList = new List<ComposablePartDefinition>();
+                                    }
+                                    reachablePartList.Add(candidateReachablePart);
+                                }
+                            }
+                        }
+                    }
+                }
+
+                reachableParts = reachablePartList;
+                return (reachableParts != null);
+            }
+        }
+    }
+}