| File: System\ComponentModel\Composition\Primitives\ComposablePartCatalog.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.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; using Microsoft.Internal; using Microsoft.Internal.Collections; namespace System.ComponentModel.Composition.Primitives { /// <summary> /// Defines the <see langword="abstract"/> base class for composable part catalogs, which produce /// and return <see cref="ComposablePartDefinition"/> objects. /// </summary> /// <remarks> /// This type is thread safe. /// </remarks> [DebuggerTypeProxy(typeof(ComposablePartCatalogDebuggerProxy))] public abstract class ComposablePartCatalog : IEnumerable<ComposablePartDefinition>, IDisposable { private bool _isDisposed; private IQueryable<ComposablePartDefinition>? _queryableParts; internal static readonly List<Tuple<ComposablePartDefinition, ExportDefinition>> _EmptyExportsList = new List<Tuple<ComposablePartDefinition, ExportDefinition>>(); /// <summary> /// Initializes a new instance of the <see cref="ComposablePartCatalog"/> class. /// </summary> protected ComposablePartCatalog() { } /// <summary> /// Gets the part definitions of the catalog. /// </summary> /// <value> /// A <see cref="IQueryable{T}"/> of <see cref="ComposablePartDefinition"/> objects of the /// <see cref="ComposablePartCatalog"/>. /// </value> /// <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"/>. /// </note> /// </remarks> [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)] public virtual IQueryable<ComposablePartDefinition> Parts { get { ThrowIfDisposed(); if (_queryableParts == null) { // Guarantee one time only set _queryableParts var p = this.AsQueryable(); Interlocked.CompareExchange(ref _queryableParts, p, null); if (_queryableParts == null) { throw new Exception(SR.Diagnostic_InternalExceptionMessage); } } return _queryableParts; } } /// <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 virtual IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> GetExports(ImportDefinition definition) { ThrowIfDisposed(); Requires.NotNull(definition, nameof(definition)); List<Tuple<ComposablePartDefinition, ExportDefinition>>? exports = null; var candidateParts = GetCandidateParts(definition); if (candidateParts != null) { foreach (var part in candidateParts) { if (part.TryGetExports(definition, out Tuple<ComposablePartDefinition, ExportDefinition>? singleMatch, out IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>>? multipleMatches)) { exports = exports.FastAppendToListAllowNulls(singleMatch, multipleMatches); } } } Debug.Assert(exports != null || _EmptyExportsList != null); return exports ?? _EmptyExportsList; } internal virtual IEnumerable<ComposablePartDefinition>? GetCandidateParts(ImportDefinition definition) { return this; } /// <summary> /// Releases the unmanaged and managed resources used by the <see cref="ComposablePartCatalog"/>. /// </summary> public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { _isDisposed = true; } [DebuggerStepThrough] private void ThrowIfDisposed() { if (_isDisposed) { throw ExceptionBuilder.CreateObjectDisposed(this); } } // // If neither Parts nor GetEnumerator() is overridden then return an empty list // If GetEnumerator is overridden this code should not be invoked: ReferenceAssemblies mark it as Abstract or Not present // We verify whether Parts is overridden by seeing if the object returns matched the one cached for this instance // Note: a query object is only cached if Parts is invoked on a catalog which did not implement it // Because reference assemblies do not expose Parts and we no longer use it, it should not get invoked by 3rd parties // Because the reference assemblies mark GetEnumerator as Abstract 3rd party code should not lack an implementation // That implementation should not try to call this implementation // Our code doies delegate to Parts in the DebuggerProxies of course. // public virtual IEnumerator<ComposablePartDefinition> GetEnumerator() { var parts = Parts; if (object.ReferenceEquals(parts, _queryableParts)) { return Enumerable.Empty<ComposablePartDefinition>().GetEnumerator(); } return parts.GetEnumerator(); } Collections.IEnumerator Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } } }