| File: System\ComponentModel\Composition\Primitives\Export.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.Threading; using Microsoft.Internal; namespace System.ComponentModel.Composition.Primitives { /// <summary> /// Represents an export. That is, a type that is made up of a delay-created exported value /// and metadata that describes that object. /// </summary> public class Export { private readonly ExportDefinition? _definition; private readonly Func<object?>? _exportedValueGetter; private static readonly object _EmptyValue = new object(); private object? _exportedValue = Export._EmptyValue; /// <summary> /// Initializes a new instance of the <see cref="Export"/> class. /// </summary> /// <remarks> /// <note type="inheritinfo"> /// Derived types calling this constructor must override <see cref="Definition"/> /// and <see cref="GetExportedValueCore"/>. /// </note> /// </remarks> protected Export() { } /// <summary> /// Initializes a new instance of the <see cref="Export"/> class /// with the specified contract name and exported value getter. /// </summary> /// <param name="contractName"> /// A <see cref="string"/> containing the contract name of the /// <see cref="Export"/>. /// </param> /// <param name="exportedValueGetter"> /// A <see cref="Func{T}"/> that is called to create the exported value of the /// <see cref="Export"/>. This allows the creation of the object to be delayed /// </param> /// <exception cref="ArgumentNullException"> /// <paramref name="contractName"/> is <see langword="null"/>. /// <para> /// -or- /// </para> /// <paramref name="exportedValueGetter"/> is <see langword="null"/>. /// </exception> /// <exception cref="ArgumentException"> /// <paramref name="contractName"/> is an empty string (""). /// </exception> public Export(string contractName, Func<object?> exportedValueGetter) : this(new ExportDefinition(contractName, (IDictionary<string, object?>?)null), exportedValueGetter) { } /// <summary> /// Initializes a new instance of the <see cref="Export"/> class /// with the specified contract name, metadata and exported value getter. /// </summary> /// <param name="contractName"> /// A <see cref="string"/> containing the contract name of the /// <see cref="Export"/>. /// </param> /// <param name="metadata"> /// An <see cref="IDictionary{TKey, TValue}"/> containing the metadata of the /// <see cref="Export"/>; or <see langword="null"/> to set the /// <see cref="Metadata"/> property to an empty, read-only /// <see cref="IDictionary{TKey, TValue}"/>. /// </param> /// <param name="exportedValueGetter"> /// A <see cref="Func{T}"/> that is called to create the exported value of the /// <see cref="Export"/>. This allows the creation of the object to be delayed. /// </param> /// <exception cref="ArgumentNullException"> /// <paramref name="contractName"/> is <see langword="null"/>. /// <para> /// -or- /// </para> /// <paramref name="exportedValueGetter"/> is <see langword="null"/>. /// </exception> /// <exception cref="ArgumentException"> /// <paramref name="contractName"/> is an empty string (""). /// </exception> public Export(string contractName, IDictionary<string, object?>? metadata, Func<object?> exportedValueGetter) : this(new ExportDefinition(contractName, metadata), exportedValueGetter) { } /// <summary> /// Initializes a new instance of the <see cref="Export"/> class /// with the specified export definition and exported value getter. /// </summary> /// <param name="definition"> /// An <see cref="ExportDefinition"/> that describes the contract that the /// <see cref="Export"/> satisfies. /// </param> /// <param name="exportedValueGetter"> /// A <see cref="Func{T}"/> that is called to create the exported value of the /// <see cref="Export"/>. This allows the creation of the object to be delayed. /// </param> /// <exception cref="ArgumentNullException"> /// <paramref name="definition"/> is <see langword="null"/>. /// <para> /// -or- /// </para> /// <paramref name="exportedValueGetter"/> is <see langword="null"/>. /// </exception> public Export(ExportDefinition definition, Func<object?> exportedValueGetter) { Requires.NotNull(definition, nameof(definition)); Requires.NotNull(exportedValueGetter, nameof(exportedValueGetter)); _definition = definition; _exportedValueGetter = exportedValueGetter; } /// <summary> /// Gets the definition that describes the contract that the export satisfies. /// </summary> /// <value> /// An <see cref="ExportDefinition"/> that describes the contract that /// the <see cref="Export"/> satisfies. /// </value> /// <exception cref="NotImplementedException"> /// This property was not overridden by a derived class. /// </exception> /// <remarks> /// <note type="inheritinfo"> /// Overriders of this property should never return /// <see langword="null"/>. /// </note> /// </remarks> public virtual ExportDefinition Definition { get { if (_definition != null) { return _definition; } throw ExceptionBuilder.CreateNotOverriddenByDerived("Definition"); } } /// <summary> /// Gets the metadata of the export. /// </summary> /// <value> /// An <see cref="IDictionary{TKey, TValue}"/> containing the metadata of the /// <see cref="Export"/>. /// </value> /// <exception cref="NotImplementedException"> /// The <see cref="Definition"/> property was not overridden by a derived class. /// </exception> /// <remarks> /// <para> /// This property returns the value of <see cref="ExportDefinition.Metadata"/> /// of the <see cref="Definition"/> property. /// </para> /// </remarks> public IDictionary<string, object?> Metadata { get { Debug.Assert(Definition.Metadata != null); return Definition.Metadata; } } /// <summary> /// Returns the exported value of the export. /// </summary> /// <returns> /// The exported <see cref="object"/> of the <see cref="Export"/>. /// </returns> /// <exception cref="CompositionException"> /// An error occurred during composition. <see cref="CompositionException.Errors"/> will /// contain a collection of errors that occurred. /// </exception> /// <exception cref="CompositionContractMismatchException"> /// The current instance is an instance of <see cref="Lazy{T}"/> and the underlying /// exported value cannot be cast to <c>T</c>. /// </exception> /// <exception cref="NotImplementedException"> /// The <see cref="GetExportedValueCore"/> method was not overridden by a derived class. /// </exception> public object? Value { get { // NOTE : the logic below guarantees that the value will be set exactly once. It DOES NOT, however, guarantee that GetExportedValueCore() will be executed // only once, as locking would be required for that. The said locking is problematic, as we can't reliable call 3rd party code under a lock. if (_exportedValue == Export._EmptyValue) { object? exportedValue = GetExportedValueCore(); Interlocked.CompareExchange(ref _exportedValue, exportedValue, Export._EmptyValue); } return _exportedValue; } } /// <summary> /// Returns the exported value of the export. /// </summary> /// <returns> /// The exported <see cref="object"/> of the <see cref="Export"/>. /// </returns> /// <exception cref="CompositionException"> /// An error occurred during composition. <see cref="CompositionException.Errors"/> will /// contain a collection of errors that occurred. /// </exception> /// <exception cref="CompositionContractMismatchException"> /// The current instance is an instance of <see cref="Lazy{T}"/> and the underlying /// exported value cannot be cast to <c>T</c>. /// </exception> /// <exception cref="NotImplementedException"> /// The method was not overridden by a derived class. /// </exception> /// <remarks> /// <note type="inheritinfo"> /// Overriders of this method should never return /// <see langword="null"/>. /// </note> /// </remarks> protected virtual object? GetExportedValueCore() { if (_exportedValueGetter != null) { return _exportedValueGetter.Invoke(); } throw ExceptionBuilder.CreateNotOverriddenByDerived("GetExportedValueCore"); } } }