【问题标题】:dynamic method invocation in expression tree表达式树中的动态方法调用
【发布时间】:2014-01-04 08:36:00
【问题描述】:

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

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

private Dictionary<string, Delegate> _externalSymbols;

private Expression _forExternalSymbol(string identifier)
{
    Delegate method = _externalSymbols[identifier];
    return Expression.Call(method.Method);
}

只要从字典中提取的method 是在编译时创建的,它就可以工作。但是,如果Func&lt;T&gt; 是动态方法,例如通过在运行时编译另一个表达式,这将无法抛出

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)。

【问题讨论】:

  • 论据呢?这些方法是否接受任何参数?
  • @nightwatch 无参数,字典保证只包含Func&lt;T&gt; 代表,T 为doublestring(这些类型的列表将来可能需要扩展)。跨度>
  • 我不太懂 linq 表达式,抱歉。但是你所做的看起来像是一个动态调用,方法名称在运行时被解析。也许您可以只使用动态对象作为外部函数的接口?

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


【解决方案1】:

只要从字典中提取的method 是在编译时创建的,它就可以工作

不,只要method 是静态的,它就可以工作。例如,如果委托是从其父分数引用某些内容的 lambda(即它是一个闭包),它也将不起作用。

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

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

【讨论】:

  • 嗯,实际上它适用于非静态方法(在这种情况下,必须使用重载版本,Expression.Constant(method.Target) 作为第一个参数,不好)。问题是,动态方法没有Target。您的回答正是我所需要的,谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-22
相关资源
最近更新 更多