File: System\ComponentModel\Composition\Primitives\ComposablePartDefinition.cs
Web Access
Project: src\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.CodeAnalysis;
using System.Linq;
 
namespace System.ComponentModel.Composition.Primitives
{
    /// <summary>
    ///     Defines the <see langword="abstract"/> base class for composable part definitions, which
    ///     describe, and allow the creation of, <see cref="ComposablePart"/> objects.
    /// </summary>
    public abstract class ComposablePartDefinition
    {
        internal static readonly IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> _EmptyExports = Enumerable.Empty<Tuple<ComposablePartDefinition, ExportDefinition>>();
 
        /// <summary>
        ///     Initializes a new instance of the <see cref="ComposablePartDefinition"/> class.
        /// </summary>
        protected ComposablePartDefinition()
        {
        }
 
        /// <summary>
        ///     Gets the export definitions that describe the exported values provided by parts
        ///     created by the definition.
        /// </summary>
        /// <value>
        ///     An <see cref="IEnumerable{T}"/> of <see cref="ExportDefinition"/> objects describing
        ///     the exported values provided by <see cref="ComposablePart"/> objects created by the
        ///     <see cref="ComposablePartDefinition"/>.
        /// </value>
        /// <remarks>
        ///     <note type="inheritinfo">
        ///         Overrides of this property should never return <see langword="null"/>.
        ///         If the <see cref="ComposablePart"/> objects created by the
        ///         <see cref="ComposablePartDefinition"/> do not provide exported values, return
        ///         an empty <see cref="IEnumerable{T}"/> instead.
        ///     </note>
        /// </remarks>
        public abstract IEnumerable<ExportDefinition> ExportDefinitions { get; }
 
        /// <summary>
        ///     Gets the import definitions that describe the imports required by parts created
        ///     by the definition.
        /// </summary>
        /// <value>
        ///     An <see cref="IEnumerable{T}"/> of <see cref="ImportDefinition"/> objects describing
        ///     the imports required by <see cref="ComposablePart"/> objects created by the
        ///     <see cref="ComposablePartDefinition"/>.
        /// </value>
        /// <remarks>
        ///     <note type="inheritinfo">
        ///         Overriders of this property should never return <see langword="null"/>.
        ///         If the <see cref="ComposablePart"/> objects created by the
        ///         <see cref="ComposablePartDefinition"/> do not have imports, return an empty
        ///         <see cref="IEnumerable{T}"/> instead.
        ///     </note>
        /// </remarks>
        public abstract IEnumerable<ImportDefinition> ImportDefinitions { get; }
 
        /// <summary>
        ///     Gets the metadata of the definition.
        /// </summary>
        /// <value>
        ///     An <see cref="IDictionary{TKey, TValue}"/> containing the metadata of the
        ///     <see cref="ComposablePartDefinition"/>. The default is an empty, read-only
        ///     <see cref="IDictionary{TKey, TValue}"/>.
        /// </value>
        /// <remarks>
        ///     <para>
        ///         <note type="inheritinfo">
        ///             Overriders of this property should return a read-only
        ///             <see cref="IDictionary{TKey, TValue}"/> object with a case-sensitive,
        ///             non-linguistic comparer, such as <see cref="StringComparer.Ordinal"/>,
        ///             and should never return <see langword="null"/>. If the
        ///             <see cref="ComposablePartDefinition"/> does contain metadata,
        ///             return an empty <see cref="IDictionary{TKey, TValue}"/> instead.
        ///         </note>
        ///     </para>
        /// </remarks>
        public virtual IDictionary<string, object?> Metadata
        {
            get { return MetadataServices.EmptyMetadata; }
        }
 
        /// <summary>
        ///     Creates a new instance of a part that the definition describes.
        /// </summary>
        /// <returns>
        ///     The created <see cref="ComposablePart"/>.
        /// </returns>
        /// <remarks>
        ///     <para>
        ///         <note type="inheritinfo">
        ///             Derived types overriding this method should return a new instance of a
        ///             <see cref="ComposablePart"/> on every invoke and should never return
        ///             <see langword="null"/>.
        ///         </note>
        ///     </para>
        /// </remarks>
        public abstract ComposablePart CreatePart();
 
        internal virtual bool TryGetExports(ImportDefinition definition, out Tuple<ComposablePartDefinition, ExportDefinition>? singleMatch, out IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>>? multipleMatches)
        {
            singleMatch = null;
            multipleMatches = null;
 
            List<Tuple<ComposablePartDefinition, ExportDefinition>>? multipleExports = null;
            Tuple<ComposablePartDefinition, ExportDefinition>? singleExport = null;
            bool matchesFound = false;
            foreach (var export in ExportDefinitions)
            {
                if (definition.IsConstraintSatisfiedBy(export))
                {
                    matchesFound = true;
                    if (singleExport == null)
                    {
                        singleExport = new Tuple<ComposablePartDefinition, ExportDefinition>(this, export);
                    }
                    else
                    {
                        if (multipleExports == null)
                        {
                            multipleExports = new List<Tuple<ComposablePartDefinition, ExportDefinition>>();
                            multipleExports.Add(singleExport);
                        }
                        multipleExports.Add(new Tuple<ComposablePartDefinition, ExportDefinition>(this, export));
                    }
                }
            }
 
            if (!matchesFound)
            {
                return false;
            }
 
            if (multipleExports != null)
            {
                multipleMatches = multipleExports;
            }
            else
            {
                singleMatch = singleExport;
            }
            return true;
        }
 
        internal virtual ComposablePartDefinition? GetGenericPartDefinition()
        {
            return null;
        }
    }
}