File: System\ComponentModel\Composition\ReflectionModel\ExportingMember.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.Globalization;
using System.Reflection;
using System.Threading;
 
namespace System.ComponentModel.Composition.ReflectionModel
{
    internal sealed class ExportingMember
    {
        private readonly ExportDefinition _definition;
        private readonly ReflectionMember _member;
        private object? _cachedValue;
        private volatile bool _isValueCached;
 
        public ExportingMember(ExportDefinition definition, ReflectionMember member)
        {
            ArgumentNullException.ThrowIfNull(definition);
            ArgumentNullException.ThrowIfNull(member);
 
            _definition = definition;
            _member = member;
        }
 
        public bool RequiresInstance
        {
            get { return _member.RequiresInstance; }
        }
 
        public ExportDefinition Definition
        {
            get { return _definition; }
        }
 
        public object? GetExportedValue(object? instance, object @lock)
        {
            EnsureReadable();
 
            if (!_isValueCached)
            {
                object? exportedValue;
                try
                {
                    exportedValue = _member.GetValue(instance);
                }
                catch (TargetInvocationException exception)
                {   // Member threw an exception. Avoid letting this
                    // leak out as a 'raw' unhandled exception, instead,
                    // we'll add some context and rethrow.
 
                    throw new ComposablePartException(
                        SR.Format(
                            SR.ReflectionModel_ExportThrewException,
                            _member.GetDisplayName()),
                        Definition.ToElement(),
                        exception.InnerException);
                }
                catch (TargetParameterCountException exception)
                {
                    // Exception was a TargetParameterCountException this occurs when we try to get an Indexer that has an Export
                    // this is not supported in MEF currently.  Ideally we would validate against it, however, we already shipped
                    // so we will turn it into a ComposablePartException instead, that they should already be prepared for
                    throw new ComposablePartException(
                        SR.Format(
                        SR.ExportNotValidOnIndexers,
                        _member.GetDisplayName()),
                        Definition.ToElement(),
                        exception.InnerException);
                }
 
                lock (@lock)
                {
                    if (!_isValueCached)
                    {
                        _cachedValue = exportedValue;
                        Thread.MemoryBarrier();
 
                        _isValueCached = true;
                    }
                }
            }
 
            return _cachedValue;
        }
 
        private void EnsureReadable()
        {
            if (!_member.CanRead)
            {   // Property does not have a getter
 
                throw new ComposablePartException(
                    SR.Format(
                        SR.ReflectionModel_ExportNotReadable,
                        _member.GetDisplayName()),
                    Definition.ToElement());
            }
        }
    }
}