2015-07-22 85 views
1

我有一个表达的getter这样的:转换通用吸气表达反对吸气式

var expression =() => SomeInstance.Nr; 

它传递给方法:

public void AddExpression<T>(Expression<Func<T>> func) 

现在我想转换是通用的表达

Expression<Func<object>> 

我不是很肯定,如果我甚至可以做到这一点。我想是这样的:

var converted = Expression.Convert(func, typeof(object)); 
var objectExpression = Expression.Lambda<Func<object>>(Expression.Call(converted.Method), func.Parameters); 

但是,当我打电话

var number = objectExpression.Compile()(); 

它不会返回属性值。

的代码可以在这里进行测试: http://volatileread.com/utilitylibrary/snippetcompiler?id=25062

更新: 看来,调用上缠绕有第二次:

var converted = Expression.Convert(func, typeof(object)); 
var objectExpression = Expression.Lambda<Func<object>>(Expression.Call(converted.Method), func.Parameters); 
var anotherDelegate = objectExpression.Compile().Invoke(); // would have expected the value here 
var value = ((Delegate)anotherDelegate).DynamicInvoke(); // this now does return the value 

回答

3

不要使用委托Expression.Call - 这只是那里调用方法。相反,您想使用Expression.Invoke,这是专门用于调用代表的。此外,关键在做表达式树是包装 - 调用内部的委托,转换的结果,并在拉姆达把这个包:

Expression<Func<int>> inputExpression =() => 42; 

var newLambda = 
    Expression.Lambda<Func<object>> 
    (
     Expression.Convert 
     (
      Expression.Invoke(inputExpression), 
      typeof(object) 
     ) 
    ); 

Console.WriteLine(newLambda.Compile()()); // Prints 42. 

newLambdaExpression<Func<object>>并调用它给你42,如你期望。

当然,这使得将其作为扩展方法变得相当容易(尽管如果需要它们,您可能希望使用模板生成所有不同的Func<...>重载)。

注意,这只会如果任何LINQ提供你实际上使用工作支持Invoke - 在这种情况下,它不是一个问题,因为拉姆达编译器可以处理它,但如果你需要使用的东西像这样与例如EntityFramework,你需要采取稍微不同的方法 - 你需要解开内部lambda,转换内部lambda的身体,然后再包裹它在另一个lambda。对于一个无参数的表达,这是相当容易:

Expression<Func<int>> inputExpression =() => 42; 

var newLambda = 
    Expression.Lambda<Func<object>> 
    (
    Expression.Convert(inputExpression.Body, typeof(object)) 
); 

Console.WriteLine(newLambda.Compile()()); // Prints 42. 

而且,完整性,注意,这仅仅在进行内表达确实是一个常量表达式,而不是报价 - 但如果你需要引用嵌套表达式,你可能不会问这个问题:D

+0

我没有'转储'可用这是在.net 4.5? (我在4.0上工作) – derape

+0

@derape这只是LINQPad辅助方法 - 它就像一个超级权力的'Console.WriteLine' :) – Luaan

+0

Thanks =)适合我! – derape