1 // -----------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 // -----------------------------------------------------------------------
5 using System
.Collections
.Generic
;
6 using System
.ComponentModel
.Composition
.Primitives
;
7 using System
.Diagnostics
;
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
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.
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
));
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
))
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)
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
141 partsToUnindex
[index
] = null;
145 AddIndexEntries(partManager
);
149 foreach (var partManager
in partsToUnindex
)
151 if (partManager
!= null)
153 RemoveIndexEntries(partManager
);