| File: System\Composition\TypedParts\TypedPartExportDescriptorProvider.cs | Web Access |
| Project: src\runtime\src\libraries\System.Composition.TypedParts\src\System.Composition.TypedParts.csproj (System.Composition.TypedParts) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.Composition.Convention; using System.Composition.Hosting.Core; using System.Composition.TypedParts.ActivationFeatures; using System.Composition.TypedParts.Discovery; using System.Linq; using System.Reflection; namespace System.Composition.TypedParts { internal sealed class TypedPartExportDescriptorProvider : ExportDescriptorProvider { private readonly Dictionary<CompositionContract, ICollection<DiscoveredExport>> _discoveredParts = new Dictionary<CompositionContract, ICollection<DiscoveredExport>>(); public TypedPartExportDescriptorProvider(IEnumerable<Type> types, AttributedModelProvider attributeContext) { var activationFeatures = CreateActivationFeatures(attributeContext); var typeInspector = new TypeInspector(attributeContext, activationFeatures); foreach (var type in types) { DiscoveredPart part; if (typeInspector.InspectTypeForPart(type.GetTypeInfo(), out part)) { AddDiscoveredPart(part); } } } private void AddDiscoveredPart(DiscoveredPart part) { foreach (var export in part.DiscoveredExports) { AddDiscoveredExport(export); } } private void AddDiscoveredExport(DiscoveredExport export, CompositionContract contract = null) { var actualContract = contract ?? export.Contract; ICollection<DiscoveredExport> forKey; if (!_discoveredParts.TryGetValue(actualContract, out forKey)) { forKey = new List<DiscoveredExport>(); _discoveredParts.Add(actualContract, forKey); } forKey.Add(export); } public override IEnumerable<ExportDescriptorPromise> GetExportDescriptors(CompositionContract contract, DependencyAccessor definitionAccessor) { DiscoverGenericParts(contract); DiscoverConstrainedParts(contract); ICollection<DiscoveredExport> forKey; if (!_discoveredParts.TryGetValue(contract, out forKey)) return NoExportDescriptors; // Exports with metadata may be matched via metadata constraints. // It should be possible to do this more aggressively by changing the way // exports are stored. if (!forKey.Any(x => x.Metadata.Any())) { // Allow some garbage to be collected _discoveredParts.Remove(contract); } return forKey.Select(de => de.GetExportDescriptorPromise(contract, definitionAccessor)).ToArray(); } // If the contract has metadata constraints, look for exports with matching metadata. private void DiscoverConstrainedParts(CompositionContract contract) { if (contract.MetadataConstraints != null) { var unconstrained = new CompositionContract(contract.ContractType, contract.ContractName); DiscoverGenericParts(unconstrained); ICollection<DiscoveredExport> forKey; if (_discoveredParts.TryGetValue(unconstrained, out forKey)) { foreach (var export in forKey) { var subsettedConstraints = contract.MetadataConstraints.Where(c => export.Metadata.ContainsKey(c.Key)).ToDictionary(c => c.Key, c => export.Metadata[c.Key]); if (subsettedConstraints.Count != 0) { var constrainedSubset = new CompositionContract(unconstrained.ContractType, unconstrained.ContractName, subsettedConstraints); if (constrainedSubset.Equals(contract)) AddDiscoveredExport(export, contract); } } } } } // If the contract is a closed generic, look for open generics // that close it. private void DiscoverGenericParts(CompositionContract contract) { if (!contract.ContractType.IsConstructedGenericType) return; var gtd = contract.ContractType.GetGenericTypeDefinition(); var openGenericContract = contract.ChangeType(gtd); ICollection<DiscoveredExport> openGenericParts; if (!_discoveredParts.TryGetValue(openGenericContract, out openGenericParts)) return; var typeArguments = contract.ContractType.GenericTypeArguments; foreach (var open in openGenericParts) { DiscoveredPart closed; if (open.Part.TryCloseGenericPart(typeArguments, out closed)) AddDiscoveredPart(closed); } } private static ActivationFeature[] CreateActivationFeatures(AttributedModelProvider attributeContext) { return new ActivationFeature[] { new DisposalFeature(), new PropertyInjectionFeature(attributeContext), new OnImportsSatisfiedFeature(attributeContext), new LifetimeFeature(), }; } internal static ActivationFeature[] DebugGetActivationFeatures(AttributedModelProvider attributeContext) { return CreateActivationFeatures(attributeContext); } } }