File: System\ComponentModel\Composition\Hosting\CatalogExportProvider.CatalogExport.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.ComponentModel.Composition.Primitives;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
 
namespace System.ComponentModel.Composition.Hosting
{
    public partial class CatalogExportProvider
    {
        private class CatalogExport : Export
        {
            protected readonly CatalogExportProvider _catalogExportProvider;
            protected readonly ComposablePartDefinition _partDefinition;
            protected readonly ExportDefinition _definition;
 
            public CatalogExport(CatalogExportProvider catalogExportProvider,
                ComposablePartDefinition partDefinition, ExportDefinition definition)
            {
                _catalogExportProvider = catalogExportProvider;
                _partDefinition = partDefinition;
                _definition = definition;
            }
 
            public override ExportDefinition Definition
            {
                get
                {
                    return _definition;
                }
            }
 
            protected virtual bool IsSharedPart
            {
                get
                {
                    return true;
                }
            }
 
            protected CatalogPart GetPartCore()
            {
                return _catalogExportProvider.GetComposablePart(_partDefinition, IsSharedPart);
            }
 
            protected void DisposePartCore(CatalogPart part, object? value)
            {
                _catalogExportProvider.DisposePart(value, part, null);
            }
 
            protected virtual CatalogPart GetPart()
            {
                return GetPartCore();
            }
 
            protected override object? GetExportedValueCore()
            {
                return _catalogExportProvider.GetExportedValue(GetPart(), _definition, IsSharedPart);
            }
 
            public static CatalogExport CreateExport(CatalogExportProvider catalogExportProvider,
                ComposablePartDefinition partDefinition, ExportDefinition definition, CreationPolicy importCreationPolicy)
            {
                CreationPolicy partPolicy = partDefinition.Metadata.GetValue<CreationPolicy>(CompositionConstants.PartCreationPolicyMetadataName);
                bool isSharedPart = ShouldUseSharedPart(partPolicy, importCreationPolicy);
 
                if (isSharedPart)
                {
                    return new CatalogExport(catalogExportProvider, partDefinition, definition);
                }
                else
                {
                    return new NonSharedCatalogExport(catalogExportProvider, partDefinition, definition);
                }
            }
 
            private static bool ShouldUseSharedPart(CreationPolicy partPolicy, CreationPolicy importPolicy)
            {
                // Matrix that details which policy to use for a given part to satisfy a given import.
                //                   Part.Any   Part.Shared  Part.NonShared
                // Import.Any        Shared     Shared       NonShared
                // Import.Shared     Shared     Shared       N/A
                // Import.NonShared  NonShared  N/A          NonShared
 
                switch (partPolicy)
                {
                    case CreationPolicy.Any:
                        {
                            if (importPolicy == CreationPolicy.Any ||
                                importPolicy == CreationPolicy.Shared)
                            {
                                return true;
                            }
                            return false;
                        }
 
                    case CreationPolicy.NonShared:
                        {
                            if (importPolicy == CreationPolicy.Shared)
                            {
                                throw new Exception(SR.Diagnostic_InternalExceptionMessage);
                            }
                            return false;
                        }
 
                    default:
                        {
                            if (partPolicy != CreationPolicy.Shared || importPolicy == CreationPolicy.NonShared)
                            {
                                throw new Exception(SR.Diagnostic_InternalExceptionMessage);
                            }
                            return true;
                        }
                }
            }
        }
 
        private sealed class NonSharedCatalogExport : CatalogExport, IDisposable
        {
            private CatalogPart? _part;
            private readonly object _lock = new object();
 
            public NonSharedCatalogExport(CatalogExportProvider catalogExportProvider,
                ComposablePartDefinition partDefinition, ExportDefinition definition)
                : base(catalogExportProvider, partDefinition, definition)
            {
            }
 
            protected override CatalogPart GetPart()
            {
                // we need to ensure that the part gets created only once, as the export contract requires that the same value be returned on subsequent calls
                if (_part == null)
                {
                    CatalogPart? part = GetPartCore();
 
                    lock (_lock)
                    {
                        if (_part == null)
                        {
                            Thread.MemoryBarrier();
                            _part = part;
                            part = null;
                        }
                    }
 
                    if (part != null)
                    {
                        DisposePartCore(part, null);
                    }
                }
 
                return _part;
            }
 
            protected override bool IsSharedPart
            {
                get
                {
                    return false;
                }
            }
 
            void IDisposable.Dispose()
            {
                if (_part != null)
                {
                    DisposePartCore(_part, Value);
                    _part = null;
                }
            }
        }
    }
}