在编译时不知道目标类型的情况下使用 Expression 获取属性值
Get property value with Expression without knowing target type at compile time
我正在尝试创建一个表达式 lambda 来传递一个对象,然后获取命名属性 return 的值。但是,该类型仅在运行时已知。
我开始使用以下方法来处理编译时已知的类型:
private static Func<T, object> CreateExpression(string propertyName)
{
var arg = Expression.Parameter(typeof(T));
var expr = Expression.Property(arg, propertyName);
return Expression.Lambda<Func<T, object>>(expr, arg).Compile();
}
效果很好。但是,我需要更改它以处理仅在运行时已知的类型。
我应该可以这样调用委托:
public object GetPropertyValue(object obj)
{
var propertyDelegate = GetDelegate(typeof(obj));
var propertyValue = propertyDelegate (obj);
return propertyValue;
}
private Func<object, object> GetDelegate(Type type)
{
// Lookup delegate in dictionary, or create if not existing
return CreateDelegate("MyProperty", type);
}
我尝试更改之前的 CreateDelegate,但它不适用于 Func<object, object>
:
Func<object,object> CreateDelegate(string propertyName, Type targetType)
{
var arg = Expression.Parameter(type);
var body = Expression.Property(arg, name);
var lambda = Expression.Lambda<Func<object,object>>(body, arg); //ArgumentException
return lambda.Compile();
}
它不会接受 Expresion.Parameter,因为它是 'targetType' 类型,而不是 'object'.
类型
我需要 Expression.Convert 什么的吗?
注意:delegate会被多次调用(Filtering方法),所以需要编译,保证性能。
编辑:解决方案(由 Marc Gravell 提供)
变量 'body' 应更改为以下内容:
var body = Expression.Convert(
Expression.Property(
Expression.Convert(arg, type),
name),
typeof(object));
内部Convert
将输入参数转换为对象,外部Convert
将return值转换。
是:
var arg = Expression.Parameter(typeof(object));
var expr = Expression.Property(Expression.Convert(arg, type), propertyName);
注意:return类型(object
)意味着很多类型需要装箱。既然你提到你这样做是为了过滤:如果可能的话,尽量通过创建一个 Func<object,bool>
来避免这个框,它在内部进行任何比较等而不装箱。
我正在尝试创建一个表达式 lambda 来传递一个对象,然后获取命名属性 return 的值。但是,该类型仅在运行时已知。
我开始使用以下方法来处理编译时已知的类型:
private static Func<T, object> CreateExpression(string propertyName)
{
var arg = Expression.Parameter(typeof(T));
var expr = Expression.Property(arg, propertyName);
return Expression.Lambda<Func<T, object>>(expr, arg).Compile();
}
效果很好。但是,我需要更改它以处理仅在运行时已知的类型。
我应该可以这样调用委托:
public object GetPropertyValue(object obj)
{
var propertyDelegate = GetDelegate(typeof(obj));
var propertyValue = propertyDelegate (obj);
return propertyValue;
}
private Func<object, object> GetDelegate(Type type)
{
// Lookup delegate in dictionary, or create if not existing
return CreateDelegate("MyProperty", type);
}
我尝试更改之前的 CreateDelegate,但它不适用于 Func<object, object>
:
Func<object,object> CreateDelegate(string propertyName, Type targetType)
{
var arg = Expression.Parameter(type);
var body = Expression.Property(arg, name);
var lambda = Expression.Lambda<Func<object,object>>(body, arg); //ArgumentException
return lambda.Compile();
}
它不会接受 Expresion.Parameter,因为它是 'targetType' 类型,而不是 'object'.
类型我需要 Expression.Convert 什么的吗?
注意:delegate会被多次调用(Filtering方法),所以需要编译,保证性能。
编辑:解决方案(由 Marc Gravell 提供)
变量 'body' 应更改为以下内容:
var body = Expression.Convert(
Expression.Property(
Expression.Convert(arg, type),
name),
typeof(object));
内部Convert
将输入参数转换为对象,外部Convert
将return值转换。
是:
var arg = Expression.Parameter(typeof(object));
var expr = Expression.Property(Expression.Convert(arg, type), propertyName);
注意:return类型(object
)意味着很多类型需要装箱。既然你提到你这样做是为了过滤:如果可能的话,尽量通过创建一个 Func<object,bool>
来避免这个框,它在内部进行任何比较等而不装箱。