| File: System\ComponentModel\Composition\Registration\PartBuilderOfT.cs | Web Access |
| Project: src\runtime\src\libraries\System.ComponentModel.Composition.Registration\src\System.ComponentModel.Composition.Registration.csproj (System.ComponentModel.Composition.Registration) |
// 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.Linq.Expressions; using System.Reflection; namespace System.ComponentModel.Composition.Registration { public class PartBuilder<T> : PartBuilder { private sealed class PropertyExpressionAdapter { private readonly PropertyInfo _propertyInfo; private readonly Action<ImportBuilder> _configureImport; private readonly Action<ExportBuilder> _configureExport; public PropertyExpressionAdapter(Expression<Func<T, object>> propertyFilter, Action<ImportBuilder> configureImport = null, Action<ExportBuilder> configureExport = null) { _propertyInfo = SelectProperties(propertyFilter); _configureImport = configureImport; _configureExport = configureExport; } public bool VerifyPropertyInfo(PropertyInfo pi) { return pi == _propertyInfo; } public void ConfigureImport(PropertyInfo _, ImportBuilder importBuilder) { _configureImport?.Invoke(importBuilder); } public void ConfigureExport(PropertyInfo _, ExportBuilder exportBuilder) { _configureExport?.Invoke(exportBuilder); } private static PropertyInfo SelectProperties(Expression<Func<T, object>> propertyFilter) { ArgumentNullException.ThrowIfNull(propertyFilter); Expression expr = Reduce(propertyFilter).Body; if (expr.NodeType == ExpressionType.MemberAccess) { MemberInfo memberInfo = ((MemberExpression)expr).Member; if (memberInfo.MemberType == MemberTypes.Property) { return (PropertyInfo)memberInfo; } } // An error occurred the expression must be a Property Member Expression throw new ArgumentException(SR.Format(SR.Argument_ExpressionMustBePropertyMember, nameof(propertyFilter)), nameof(propertyFilter)); } private static Expression<Func<T, object>> Reduce(Expression<Func<T, object>> expr) { while (expr.CanReduce) { expr = (Expression<Func<T, object>>)expr.Reduce(); } return expr; } } private sealed class ConstructorExpressionAdapter { private ConstructorInfo _constructorInfo; private Dictionary<ParameterInfo, Action<ImportBuilder>> _importBuilders; public ConstructorExpressionAdapter(Expression<Func<ParameterImportBuilder, T>> selectConstructor) { ParseSelectConstructor(selectConstructor); } public ConstructorInfo SelectConstructor(ConstructorInfo[] _) { return _constructorInfo; } public void ConfigureConstructorImports(ParameterInfo parameterInfo, ImportBuilder importBuilder) { if (_importBuilders != null && _importBuilders.TryGetValue(parameterInfo, out Action<ImportBuilder> parameterImportBuilder)) { parameterImportBuilder(importBuilder); } } private void ParseSelectConstructor(Expression<Func<ParameterImportBuilder, T>> constructorFilter) { ArgumentNullException.ThrowIfNull(constructorFilter); Expression expr = Reduce(constructorFilter).Body; if (expr.NodeType != ExpressionType.New) { throw new ArgumentException(SR.Format(SR.Argument_ExpressionMustBePropertyMember, nameof(constructorFilter)), nameof(constructorFilter)); } var newExpression = (NewExpression)expr; _constructorInfo = newExpression.Constructor; int index = 0; ParameterInfo[] parameterInfos = _constructorInfo.GetParameters(); foreach (Expression argument in newExpression.Arguments) { if (argument.NodeType == ExpressionType.Call) { var methodCallExpression = (MethodCallExpression)argument; if (methodCallExpression.Arguments.Count == 1) { Expression parameter = methodCallExpression.Arguments[0]; if (parameter.NodeType == ExpressionType.Lambda) { var lambdaExpression = (LambdaExpression)parameter; Delegate importDelegate = lambdaExpression.Compile(); _importBuilders ??= new Dictionary<ParameterInfo, Action<ImportBuilder>>(); _importBuilders.Add(parameterInfos[index], (Action<ImportBuilder>)importDelegate); ++index; } } } } } private static Expression<Func<ParameterImportBuilder, T>> Reduce(Expression<Func<ParameterImportBuilder, T>> expr) { while (expr.CanReduce) { expr.Reduce(); } return expr; } } internal PartBuilder(Predicate<Type> selectType) : base(selectType) { } public PartBuilder<T> SelectConstructor(Expression<Func<ParameterImportBuilder, T>> constructorFilter) { ArgumentNullException.ThrowIfNull(constructorFilter); var adapter = new ConstructorExpressionAdapter(constructorFilter); SelectConstructor(adapter.SelectConstructor, adapter.ConfigureConstructorImports); return this; } public PartBuilder<T> ExportProperty(Expression<Func<T, object>> propertyFilter) { return ExportProperty(propertyFilter, null); } public PartBuilder<T> ExportProperty( Expression<Func<T, object>> propertyFilter, Action<ExportBuilder> exportConfiguration) { ArgumentNullException.ThrowIfNull(propertyFilter); var adapter = new PropertyExpressionAdapter(propertyFilter, null, exportConfiguration); ExportProperties(adapter.VerifyPropertyInfo, adapter.ConfigureExport); return this; } public PartBuilder<T> ExportProperty<TContract>(Expression<Func<T, object>> propertyFilter) { return ExportProperty<TContract>(propertyFilter, null); } public PartBuilder<T> ExportProperty<TContract>(Expression<Func<T, object>> propertyFilter, Action<ExportBuilder> exportConfiguration) { ArgumentNullException.ThrowIfNull(propertyFilter); var adapter = new PropertyExpressionAdapter(propertyFilter, null, exportConfiguration); ExportProperties<TContract>(adapter.VerifyPropertyInfo, adapter.ConfigureExport); return this; } public PartBuilder<T> ImportProperty(Expression<Func<T, object>> propertyFilter) { return ImportProperty(propertyFilter, null); } public PartBuilder<T> ImportProperty(Expression<Func<T, object>> propertyFilter, Action<ImportBuilder> importConfiguration) { ArgumentNullException.ThrowIfNull(propertyFilter); var adapter = new PropertyExpressionAdapter(propertyFilter, importConfiguration, null); ImportProperties(adapter.VerifyPropertyInfo, adapter.ConfigureImport); return this; } public PartBuilder<T> ImportProperty<TContract>(Expression<Func<T, object>> propertyFilter) { return ImportProperty<TContract>(propertyFilter, null); } public PartBuilder<T> ImportProperty<TContract>(Expression<Func<T, object>> propertyFilter, Action<ImportBuilder> importConfiguration) { ArgumentNullException.ThrowIfNull(propertyFilter); var adapter = new PropertyExpressionAdapter(propertyFilter, importConfiguration, null); ImportProperties<TContract>(adapter.VerifyPropertyInfo, adapter.ConfigureImport); return this; } } }