| File: System\ComponentModel\Composition\Hosting\FilteredCatalog.Traversal.cs | Web Access |
| Project: src\runtime\src\libraries\System.ComponentModel.Composition\src\System.ComponentModel.Composition.csproj (System.ComponentModel.Composition) |
// 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.ComponentModel.Composition.Primitives; using System.Linq; using Microsoft.Internal; namespace System.ComponentModel.Composition.Hosting { public partial class FilteredCatalog { /// <summary> /// Creates a new instance of the <see cref="FilteredCatalog"/> that conatains all the parts from the original filtered catalog and all their dependencies. /// </summary> /// <returns></returns> public FilteredCatalog IncludeDependencies() { return IncludeDependencies(i => i.Cardinality == ImportCardinality.ExactlyOne); } /// <summary> /// Creates a new instance of the <see cref="FilteredCatalog"/> that conatains all the parts from the original filtered catalog and all their dependencies that /// can be reached via imports that match the specified filter. /// </summary> /// <param name="importFilter">The import filter.</param> /// <returns></returns> public FilteredCatalog IncludeDependencies(Func<ImportDefinition, bool> importFilter) { Requires.NotNull(importFilter, nameof(importFilter)); ThrowIfDisposed(); return Traverse(new DependenciesTraversal(this, importFilter)); } /// <summary> /// Creates a new instance of the <see cref="FilteredCatalog"/> that conatains all the parts from the original filtered catalog and all their dependents. /// </summary> /// <returns></returns> public FilteredCatalog IncludeDependents() { return IncludeDependents(i => i.Cardinality == ImportCardinality.ExactlyOne); } /// <summary> /// Creates a new instance of the <see cref="FilteredCatalog"/> that conatains all the parts from the original filtered catalog and all their dependents that /// can be reached via imports that match the specified filter. /// </summary> /// <param name="importFilter">The import filter.</param> /// <returns></returns> public FilteredCatalog IncludeDependents(Func<ImportDefinition, bool> importFilter) { Requires.NotNull(importFilter, nameof(importFilter)); ThrowIfDisposed(); return Traverse(new DependentsTraversal(this, importFilter)); } private FilteredCatalog Traverse(IComposablePartCatalogTraversal traversal) { ArgumentNullException.ThrowIfNull(traversal); // we make sure that the underlyiong catalog cannot change while we are doing the trasversal // After thaty traversal is done, the freeze is lifted, and the catalog is free to change, but the changes // cannot affect partitioning FreezeInnerCatalog(); try { traversal.Initialize(); var traversalClosure = GetTraversalClosure(_innerCatalog.Where(_filter), traversal); return new FilteredCatalog(_innerCatalog, traversalClosure.Contains); } finally { UnfreezeInnerCatalog(); } } private static HashSet<ComposablePartDefinition> GetTraversalClosure(IEnumerable<ComposablePartDefinition> parts, IComposablePartCatalogTraversal traversal) { ArgumentNullException.ThrowIfNull(traversal); var traversedParts = new HashSet<ComposablePartDefinition>(); GetTraversalClosure(parts, traversedParts, traversal); return traversedParts; } private static void GetTraversalClosure(IEnumerable<ComposablePartDefinition> parts, HashSet<ComposablePartDefinition> traversedParts, IComposablePartCatalogTraversal traversal) { foreach (var part in parts) { if (traversedParts.Add(part)) { if (traversal.TryTraverse(part, out IEnumerable<ComposablePartDefinition>? partsToTraverse)) { GetTraversalClosure(partsToTraverse, traversedParts, traversal); } } } } private void FreezeInnerCatalog() { if (_innerCatalog is INotifyComposablePartCatalogChanged innerNotifyCatalog) { innerNotifyCatalog.Changing += ThrowOnRecomposition; } } private void UnfreezeInnerCatalog() { if (_innerCatalog is INotifyComposablePartCatalogChanged innerNotifyCatalog) { innerNotifyCatalog.Changing -= ThrowOnRecomposition; } } private static void ThrowOnRecomposition(object? sender, ComposablePartCatalogChangeEventArgs e) { throw new ChangeRejectedException(); } } }