update MEF to preview 9
[mcs.git] / class / System.ComponentModel.Composition / src / ComponentModel / System / ComponentModel / Composition / Hosting / ImportEngine.RecompositionManager.cs
blobff3eb19dee6b85c33c45b86d3afed79fa22beb76
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;
8 using System.Linq;
9 using System.Runtime.CompilerServices;
10 using Microsoft.Internal;
11 using Microsoft.Internal.Collections;
13 namespace System.ComponentModel.Composition.Hosting
15 public partial class ImportEngine
17 /// <summary>
18 /// Used by the <see cref="ImportEngine"/> to effiecently store and retrieve the list of parts
19 /// that will be affected by changes to exports. This allows the <see cref="ImportEngine"/> to properly
20 /// block breaking changes and also recompose imports as appropriate.
21 /// </summary>
22 private class RecompositionManager
24 private WeakReferenceCollection<PartManager> _partsToIndex = new WeakReferenceCollection<PartManager>();
25 private WeakReferenceCollection<PartManager> _partsToUnindex = new WeakReferenceCollection<PartManager>();
26 private Dictionary<string, WeakReferenceCollection<PartManager>> _partManagerIndex = new Dictionary<string, WeakReferenceCollection<PartManager>>();
28 public void AddPartToIndex(PartManager partManager)
30 this._partsToIndex.Add(partManager);
33 public void AddPartToUnindex(PartManager partManager)
35 this._partsToUnindex.Add(partManager);
38 public IEnumerable<PartManager> GetAffectedParts(IEnumerable<string> changedContractNames)
40 this.UpdateImportIndex();
42 List<PartManager> parts = new List<PartManager>();
44 parts.AddRange(GetPartsImporting(ImportDefinition.EmptyContractName));
46 foreach (string contractName in changedContractNames)
48 parts.AddRange(GetPartsImporting(contractName));
51 return parts;
54 public static IEnumerable<ImportDefinition> GetAffectedImports(ComposablePart part, IEnumerable<ExportDefinition> changedExports)
56 return part.ImportDefinitions.Where(import => IsAffectedImport(import, changedExports));
59 private static bool IsAffectedImport(ImportDefinition import, IEnumerable<ExportDefinition> changedExports)
61 // This could be more efficient still if the export definitions were indexed by contract name,
62 // only worth revisiting if we need to squeeze more performance out of recomposition
63 foreach (var export in changedExports)
65 if (import.IsConstraintSatisfiedBy(export))
67 return true;
71 return false;
74 public IEnumerable<PartManager> GetPartsImporting(string contractName)
76 WeakReferenceCollection<PartManager> partManagerList;
77 if (!this._partManagerIndex.TryGetValue(contractName, out partManagerList))
79 return Enumerable.Empty<PartManager>();
82 return partManagerList.AliveItemsToList();
85 private void AddIndexEntries(PartManager partManager)
87 foreach (string contractName in partManager.GetImportedContractNames())
89 WeakReferenceCollection<PartManager> indexEntries;
90 if (!this._partManagerIndex.TryGetValue(contractName, out indexEntries))
92 indexEntries = new WeakReferenceCollection<PartManager>();
93 this._partManagerIndex.Add(contractName, indexEntries);
96 if (!indexEntries.Contains(partManager))
98 indexEntries.Add(partManager);
103 private void RemoveIndexEntries(PartManager partManager)
105 foreach (string contractName in partManager.GetImportedContractNames())
107 WeakReferenceCollection<PartManager> indexEntries;
108 if (this._partManagerIndex.TryGetValue(contractName, out indexEntries))
110 indexEntries.Remove(partManager);
111 var aliveItems = indexEntries.AliveItemsToList();
113 if (aliveItems.Count == 0)
115 this._partManagerIndex.Remove(contractName);
121 private void UpdateImportIndex()
123 var partsToIndex = this._partsToIndex.AliveItemsToList();
124 this._partsToIndex.Clear();
126 var partsToUnindex = this._partsToUnindex.AliveItemsToList();
127 this._partsToUnindex.Clear();
129 if (partsToIndex.Count == 0 && partsToUnindex.Count == 0)
131 return;
134 foreach (var partManager in partsToIndex)
136 var index = partsToUnindex.IndexOf(partManager);
138 // If the same part is being added and removed we can ignore both
139 if (index >= 0)
141 partsToUnindex[index] = null;
143 else
145 AddIndexEntries(partManager);
149 foreach (var partManager in partsToUnindex)
151 if (partManager != null)
153 RemoveIndexEntries(partManager);