表达式树中的动态方法调用

时间:2014-01-04 08:36:01

标签: c# .net-3.5 expression-trees dynamicmethod dynamic-method

构造表达式树时,我必须使用调用外部方法的节点来获取表达式然后可以继续评估的值。 这些方法以Func<T>提供,我的代码不知道它们的来源。

执行上述调用的最正确方法是什么?我尝试过这样的事情:

private Dictionary<string, Delegate> _externalSymbols;

private Expression _forExternalSymbol(string identifier)
{
    Delegate method = _externalSymbols[identifier];
    return Expression.Call(method.Method);
}
只要从字典中获取的method是在编译时创建的,

就可以正常工作。但是,如果Func<T>是一个动态方法,例如,通过在运行时编译另一个表达式,这将无法抛出

  

ArgumentException:为调用方法'Int32 lambda_method(System.Runtime.CompilerServices.ExecutionScope)'提供的参数数量不正确

通过将给定的函数包装到一个额外的表达式中可以实现所需的效果,但与以前的表达相比,这看起来非常可怕:

private Expression _forExternalSymbol(string identifier)
{
    Delegate method = _externalSymbols[identifier];
    Expression mediator = method is Func<double> ?
        (Expression)(Expression<Func<double>>)(() => ((Func<double>)method)()) :
        (Expression<Func<string>>)(() => ((Func<string>)method)());
    return Expression.Invoke(mediator);
}

此外,如果我需要添加对doublestring以外的类型的支持,这几乎不是一种可扩展的方法。

我想知道是否有更好的选项可以使用动态创建的方法(最好适用于.NET 3.5)。

1 个答案:

答案 0 :(得分:2)

  

只要从字典中获取的method是在编译时创建的

,就可以正常工作

不,只要method是静态的,它就会起作用。例如,如果委托是一个引用其父分数的lambda(即它是一个闭包),它也将无法工作。

调用委托的正确方法是使用Expression.Invoke()。要获得代表您的代理人的Expression,请使用Expression.Constant()

Expression.Invoke(Expression.Constant(method)))