> 对于具有属性的属性,c#,.net,reflection"/>

首页 > 解决方案 > 使用反射类型 T 来创建表达式> 对于具有属性的属性

问题描述

我目前正在探索封装一些通常是迭代的逻辑的可行性。使用第 3 方库,它具有通用 Html Helper 方法,允许您将属性从 Generic T 类映射到表组件。通常你必须写一些东西来达到以下效果:

HtmlHelper.GenerateTable<ClassName>
.configure(tableDefinition =>{
  // Adding each property you want to render here
  tableDefinition.add(myClassRef => myClassRef.propertyA);
  tableDefinition.add(myClassRef => myClassRef.propertyB);
})

我正在探索将属性添加到属性(例如标准 Display 属性)然后使用反射将该属性添加到容器的想法。该add方法只接受 type 的参数Expression<Func<T, TValue>>。以我目前对反射的理解,我知道我可以通过循环PropertyInfo并检查我想要使用的属性来识别适用的属性GetCustomAttribute

我很难过的是是否可以使用反射来提供 add 方法期望的参数类型?

我将抛出到目前为止我已经开始使用的辅助方法逻辑。我的假设是,这将引导我走向 Expression 和 Lambda 类,但我无法充实任何有效的东西,因为我在技术上没有TValue.


var t = typeof(T);
List<PropertyInfo> properties = t.GetProperties().ToList();
foreach(var prop in properties)
{
    var attr = (DisplayAttribute[])prop.GetCustomAttributes(typeof(DisplayAttribute), false);
    if (attr.Length > 0)
    {
        // TODO: Call add with expression?
    }
}

标签: c#.netreflection

解决方案


Expression您可以使用类上的方法相当容易地实现这一点。首先,使用 lambda(例如Expression<Func<A, B>> expr = x => x.PropertyA)编写表达式是最简单的,然后在调试器中检查它以查看编译器构造什么。

在你的情况下,这样的事情应该有效:

// The parameter passed into the expression (myClassRef) in your code
var parameter = Expression.Parameter(typeof(T), "myClassRef");

// Access the property described by the PropertyInfo 'prop' on the
// myClassRef parameter
var propertyAccess = Expression.Property(parameter, prop);
// Since we're returning an 'object', we'll need to make sure we box value types.
var box = Expression.Convert(propertyAccess, typeof(object));

// Construct the whole lambda
var lambda = Expression.Lambda<Func<T, object>>(box, parameter);
tableDefinition.add(lambda);

请注意,我传递的是Expression<Func<T, object>>into add,而不是Expression<Func<T, TValue>>. 我这没关系,它避免了add使用反射调用。当我编写与add过去类似的方法时,我根本不在乎TValue:我只是检查ExpressionPropertyInfo从属性访问中获取。

如果您确实需要通过 an Expression<Func<T, TValue>>,则必须执行以下操作:

var delegateType = typeof(Func<,>).MakeGenericType(typeof(T), prop.PropertyType);
var lambda = Expression.Lambda(delegateType, propertyAccess, parameter);

// I'm assuming that your `add` method looks like:
// void add<T, TValue>(Expression<Func<T, TValue>> expr)
// I'm also assuming there's only one method called 'add' -- be smarter in that
// 'GetMethod' call if not.
var addMethod = typeof(TableDefinition)
    .GetMethod("add")
    .MakeGenericMethod(typeof(T), prop.PropertyType);

addMethod.Invoke(tableDefinition, new object[] { lambda });

Expression.Convert(..., typeof(object))请注意,在这种情况下您不需要。


推荐阅读