| File: System\ComponentModel\Composition\ReflectionModel\ImportingMember.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; using System.Collections.Generic; using System.ComponentModel.Composition.Primitives; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Reflection; using Microsoft.Internal; using Microsoft.Internal.Collections; namespace System.ComponentModel.Composition.ReflectionModel { internal sealed class ImportingMember : ImportingItem { private readonly ReflectionWritableMember _member; public ImportingMember(ContractBasedImportDefinition definition, ReflectionWritableMember member, ImportType importType) : base(definition, importType) { ArgumentNullException.ThrowIfNull(member); _member = member; } public void SetExportedValue(object? instance, object value) { if (RequiresCollectionNormalization()) { SetCollectionMemberValue(instance, (IEnumerable)value); } else { SetSingleMemberValue(instance, value); } } private bool RequiresCollectionNormalization() { if (Definition.Cardinality != ImportCardinality.ZeroOrMore) { // If we're not looking at a collection import, then don't // 'normalize' the collection. return false; } if (_member.CanWrite && ImportType.IsAssignableCollectionType) { // If we can simply replace the entire value of the property/field, then // we don't need to 'normalize' the collection. return false; } return true; } private void SetSingleMemberValue(object? instance, object? value) { EnsureWritable(); try { _member.SetValue(instance, value); } 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_ImportThrewException, _member.GetDisplayName()), Definition.ToElement(), exception.InnerException); } catch (TargetParameterCountException exception) { // Exception was a TargetParameterCountException this occurs when we try to set an Indexer that has an Import // 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.ImportNotValidOnIndexers, _member.GetDisplayName()), Definition.ToElement(), exception.InnerException); } } private void EnsureWritable() { if (!_member.CanWrite) { // Property does not have a setter, or // field is marked as read-only. throw new ComposablePartException( SR.Format( SR.ReflectionModel_ImportNotWritable, _member.GetDisplayName()), Definition.ToElement()); } } private void SetCollectionMemberValue(object? instance, IEnumerable values) { ArgumentNullException.ThrowIfNull(values); ICollection<object>? collection = null; Type? itemType = CollectionServices.GetCollectionElementType(ImportType.ActualType); if (itemType != null) { collection = GetNormalizedCollection(itemType, instance); } EnsureCollectionIsWritable(collection); PopulateCollection(collection!, values); } private ICollection<object> GetNormalizedCollection(Type itemType, object? instance) { ArgumentNullException.ThrowIfNull(itemType); object? collectionObject = null; if (_member.CanRead) { try { collectionObject = _member.GetValue(instance); } catch (TargetInvocationException exception) { throw new ComposablePartException( SR.Format( SR.ReflectionModel_ImportCollectionGetThrewException, _member.GetDisplayName()), Definition.ToElement(), exception.InnerException); } } if (collectionObject == null) { ConstructorInfo? constructor = ImportType.ActualType.GetConstructor(Type.EmptyTypes); // If it contains a default public constructor create a new instance. if (constructor != null) { try { collectionObject = constructor.SafeInvoke(); } catch (TargetInvocationException exception) { throw new ComposablePartException( SR.Format( SR.ReflectionModel_ImportCollectionConstructionThrewException, _member.GetDisplayName(), ImportType.ActualType.FullName), Definition.ToElement(), exception.InnerException); } SetSingleMemberValue(instance, collectionObject); } } if (collectionObject == null) { throw new ComposablePartException( SR.Format( SR.ReflectionModel_ImportCollectionNull, _member.GetDisplayName()), Definition.ToElement()); } return CollectionServices.GetCollectionWrapper(itemType, collectionObject); } private void EnsureCollectionIsWritable(ICollection<object>? collection) { bool isReadOnly = true; try { if (collection != null) { isReadOnly = collection.IsReadOnly; } } catch (Exception exception) { throw new ComposablePartException( SR.Format( SR.ReflectionModel_ImportCollectionIsReadOnlyThrewException, _member.GetDisplayName(), collection!.GetType().FullName), Definition.ToElement(), exception); } if (isReadOnly) { throw new ComposablePartException( SR.Format( SR.ReflectionModel_ImportCollectionNotWritable, _member.GetDisplayName()), Definition.ToElement()); } } private void PopulateCollection(ICollection<object?> collection, IEnumerable values) { ArgumentNullException.ThrowIfNull(collection); ArgumentNullException.ThrowIfNull(values); try { collection.Clear(); } catch (Exception exception) { throw new ComposablePartException( SR.Format( SR.ReflectionModel_ImportCollectionClearThrewException, _member.GetDisplayName(), collection.GetType().FullName), Definition.ToElement(), exception); } foreach (object? value in values) { try { collection.Add(value); } catch (Exception exception) { throw new ComposablePartException( SR.Format( SR.ReflectionModel_ImportCollectionAddThrewException, _member.GetDisplayName(), collection.GetType().FullName), Definition.ToElement(), exception); } } } } }