| File: System\ComponentModel\Composition\Hosting\CompositionScopeDefinition.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.Diagnostics; using System.Linq; using System.Threading; using Microsoft.Internal; namespace System.ComponentModel.Composition.Hosting { [DebuggerTypeProxy(typeof(CompositionScopeDefinitionDebuggerProxy))] public class CompositionScopeDefinition : ComposablePartCatalog, INotifyComposablePartCatalogChanged { private ComposablePartCatalog? _catalog; private IEnumerable<ExportDefinition>? _publicSurface; private IEnumerable<CompositionScopeDefinition> _children = Enumerable.Empty<CompositionScopeDefinition>(); private volatile int _isDisposed; /// <summary> /// Initializes a new instance of the <see cref="CompositionScopeDefinition"/> class. /// </summary> protected CompositionScopeDefinition() { } /// <summary> /// Initializes a new instance of the <see cref="CompositionScopeDefinition"/> class. /// </summary> /// <param name="catalog">The catalog.</param> /// <param name="children">The children.</param> public CompositionScopeDefinition(ComposablePartCatalog catalog, IEnumerable<CompositionScopeDefinition> children) { Requires.NotNull(catalog, nameof(catalog)); Requires.NullOrNotNullElements(children, nameof(children)); InitializeCompositionScopeDefinition(catalog, children, null); } /// <summary> /// Initializes a new instance of the <see cref="CompositionScopeDefinition"/> class. /// </summary> /// <param name="catalog">The catalog.</param> /// <param name="children">The children.</param> /// <param name="publicSurface">The exports that can be used to create new scopes.</param> public CompositionScopeDefinition(ComposablePartCatalog catalog, IEnumerable<CompositionScopeDefinition> children, IEnumerable<ExportDefinition> publicSurface) { Requires.NotNull(catalog, nameof(catalog)); Requires.NullOrNotNullElements(children, nameof(children)); Requires.NullOrNotNullElements(publicSurface, nameof(publicSurface)); InitializeCompositionScopeDefinition(catalog, children, publicSurface); } /// <summary> /// Initializes a new instance of the <see cref="CompositionScopeDefinition"/> class. /// </summary> /// <param name="catalog">The catalog.</param> /// <param name="children">The children.</param> /// <param name="publicSurface">The exports that can be used to create new scopes.</param> private void InitializeCompositionScopeDefinition(ComposablePartCatalog catalog, IEnumerable<CompositionScopeDefinition>? children, IEnumerable<ExportDefinition>? publicSurface) { _catalog = catalog; if (children != null) { _children = children.ToArray(); } if (publicSurface != null) { _publicSurface = publicSurface; } if (_catalog is INotifyComposablePartCatalogChanged notifyCatalog) { notifyCatalog.Changed += OnChangedInternal; notifyCatalog.Changing += OnChangingInternal; } } /// <summary> /// Releases unmanaged and - optionally - managed resources /// </summary> /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> protected override void Dispose(bool disposing) { try { if (disposing) { if (Interlocked.CompareExchange(ref _isDisposed, 1, 0) == 0) { if (_catalog is INotifyComposablePartCatalogChanged notifyCatalog) { notifyCatalog.Changed -= OnChangedInternal; notifyCatalog.Changing -= OnChangingInternal; } } } } finally { base.Dispose(disposing); } } /// <summary> /// Gets the children. /// </summary> /// <value>The children.</value> public virtual IEnumerable<CompositionScopeDefinition> Children { get { ThrowIfDisposed(); return _children; } } /// <summary> /// Gets the export definitions that describe the exports surfaced by the CompositionScopedefinition. /// </summary> /// <value> /// An <see cref="IEnumerable{T}"/> of <see cref="ExportDefinition"/> objects describing /// the exports surfaced by the <see cref="CompositionScopeDefinition"/>. /// </value> /// <remarks> /// <note type="inheritinfo"> /// Overriders of this property must not return <see langword="null"/>. /// </note> /// </remarks> public virtual IEnumerable<ExportDefinition> PublicSurface { get { ThrowIfDisposed(); if (_publicSurface == null) { return this.SelectMany((p) => p.ExportDefinitions); } return _publicSurface; } } /// <summary> /// Gets an Enumerator for the ComposablePartDefinitions /// </summary> /// <value>The children.</value> public override IEnumerator<ComposablePartDefinition> GetEnumerator() { Debug.Assert(_catalog != null); return _catalog.GetEnumerator(); } /// <summary> /// Returns the export definitions that match the constraint defined by the specified definition. /// </summary> /// <param name="definition">The <see cref="ImportDefinition"/> that defines the conditions of the /// <see cref="ExportDefinition"/> objects to return.</param> /// <returns> /// An <see cref="IEnumerable{T}"/> of <see cref="Tuple{T1, T2}"/> containing the /// <see cref="ExportDefinition"/> objects and their associated /// <see cref="ComposablePartDefinition"/> for objects that match the constraint defined /// by <paramref name="definition"/>. /// </returns> /// <exception cref="ArgumentNullException"> /// <paramref name="definition"/> is <see langword="null"/>. /// </exception> /// <exception cref="ObjectDisposedException"> /// The <see cref="ComposablePartCatalog"/> has been disposed of. /// </exception> /// <remarks> /// <note type="inheritinfo"> /// Overriders of this property should never return <see langword="null"/>, if no /// <see cref="ExportDefinition"/> match the conditions defined by /// <paramref name="definition"/>, return an empty <see cref="IEnumerable{T}"/>. /// </note> /// </remarks> public override IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> GetExports(ImportDefinition definition) { ThrowIfDisposed(); Debug.Assert(_catalog != null); return _catalog.GetExports(definition); } internal IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> GetExportsFromPublicSurface(ImportDefinition definition) { ArgumentNullException.ThrowIfNull(definition); var exports = new List<Tuple<ComposablePartDefinition, ExportDefinition>>(); foreach (var exportDefinition in PublicSurface) { if (definition.IsConstraintSatisfiedBy(exportDefinition)) { foreach (var export in GetExports(definition)) { if (export.Item2 == exportDefinition) { exports.Add(export); break; } } } } return exports; } /// <summary> /// Notify when the contents of the Catalog has changed. /// </summary> public event EventHandler<ComposablePartCatalogChangeEventArgs>? Changed; /// <summary> /// Notify when the contents of the Catalog is changing. /// </summary> public event EventHandler<ComposablePartCatalogChangeEventArgs>? Changing; /// <summary> /// Raises the <see cref="Changed"/> event. /// </summary> /// <param name="e">The <see cref="System.ComponentModel.Composition.Hosting.ComposablePartCatalogChangeEventArgs"/> instance containing the event data.</param> protected virtual void OnChanged(ComposablePartCatalogChangeEventArgs e) { Changed?.Invoke(this, e); } /// <summary> /// Raises the <see cref="Changing"/> event. /// </summary> /// <param name="e">The <see cref="System.ComponentModel.Composition.Hosting.ComposablePartCatalogChangeEventArgs"/> instance containing the event data.</param> protected virtual void OnChanging(ComposablePartCatalogChangeEventArgs e) { Changing?.Invoke(this, e); } private void OnChangedInternal(object? sender, ComposablePartCatalogChangeEventArgs e) { OnChanged(e); } private void OnChangingInternal(object? sender, ComposablePartCatalogChangeEventArgs e) { OnChanging(e); } [DebuggerStepThrough] private void ThrowIfDisposed() { if (_isDisposed == 1) { throw ExceptionBuilder.CreateObjectDisposed(this); } } } }