1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Collections.Generic;
6 using Microsoft.Internal;
7 
8 namespace System.Composition.Hosting.Core
9 {
10     internal class ExportDescriptorRegistry
11     {
12         private readonly object _thisLock = new object();
13         private readonly ExportDescriptorProvider[] _exportDescriptorProviders;
14         private volatile IDictionary<CompositionContract, ExportDescriptor[]> _partDefinitions = new Dictionary<CompositionContract, ExportDescriptor[]>();
15 
ExportDescriptorRegistry(ExportDescriptorProvider[] exportDescriptorProviders)16         public ExportDescriptorRegistry(ExportDescriptorProvider[] exportDescriptorProviders)
17         {
18             _exportDescriptorProviders = exportDescriptorProviders;
19         }
20 
TryGetSingleForExport(CompositionContract exportKey, out ExportDescriptor defaultForExport)21         public bool TryGetSingleForExport(CompositionContract exportKey, out ExportDescriptor defaultForExport)
22         {
23             ExportDescriptor[] allForExport;
24             if (!_partDefinitions.TryGetValue(exportKey, out allForExport))
25             {
26                 lock (_thisLock)
27                 {
28                     if (!_partDefinitions.ContainsKey(exportKey))
29                     {
30                         var updatedDefinitions = new Dictionary<CompositionContract, ExportDescriptor[]>(_partDefinitions);
31                         var updateOperation = new ExportDescriptorRegistryUpdate(updatedDefinitions, _exportDescriptorProviders);
32                         updateOperation.Execute(exportKey);
33 
34                         _partDefinitions = updatedDefinitions;
35                     }
36                 }
37 
38                 allForExport = (ExportDescriptor[])_partDefinitions[exportKey];
39             }
40 
41             if (allForExport.Length == 0)
42             {
43                 defaultForExport = null;
44                 return false;
45             }
46 
47             // This check is duplicated in the update process- the update operation will catch
48             // cardinality violations in advance of this in all but a few very rare scenarios.
49             if (allForExport.Length != 1)
50                 throw ThrowHelper.CardinalityMismatch_TooManyExports(exportKey.ToString());
51 
52             defaultForExport = allForExport[0];
53             return true;
54         }
55     }
56 }
57