使用Expression获取属性值,而无需在编译时知道目标类型

时间:2015-01-06 09:16:57

标签: c# linq expression

我试图创建一个表达式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,因为它的类型为&#39; targetType&#39;,而不是&#39; object&#39;。

我需要Expression.Convert还是什么?

注意:委托将被多次调用(过滤方法),因此需要进行编译,以确保性能。

编辑:解决方案(由Marc Gravell提供)

变量&#39; body&#39;应更改为以下内容:

var body = Expression.Convert(
             Expression.Property(
               Expression.Convert(arg, type), 
               name), 
             typeof(object));

内部Convert将输入参数转换为对象,外部Convert转换返回值。

1 个答案:

答案 0 :(得分:3)

是:

var arg = Expression.Parameter(typeof(object));
var expr = Expression.Property(Expression.Convert(arg, type), propertyName);

注意:返回类型object)表示需要装箱很多类型。既然你提到过你这样做是为了过滤:如果可能的话,试着通过创建一个Func<object,bool>而不是装箱而在内部进行任何比较等来避免这个方框。