我正在尝试创建一个表达式lambda,以传递一个对象,然后返回命名属性的值。但是该类型只在运行时才知道。
我从以下方法开始处理在编译时已知类型:
我从以下方法开始处理在编译时已知类型:
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();
}
它不会接受Expression.Parameter,因为它的类型是'targetType'而不是'object'。
我需要使用Expression.Convert或其他什么东西吗?
注意:委托将被多次调用(过滤方法),因此需要编译以确保性能。
编辑:解决方案(由Marc Gravell提供)
变量'body'应更改为以下内容:
var body = Expression.Convert(
Expression.Property(
Expression.Convert(arg, type),
name),
typeof(object));
内部的 Convert
将输入参数转换为对象,而外部的 Convert
则将返回值进行转换。
Expression.Lambda
,你可能需要查看一下。 - RhumborlFunc<object,object>
来提高性能;使用DynamicInvoke
的Delegate
非常慢。 - Marc Gravell