表达式树中的动态方法调用(dynamic method invocation in expression tree)

在构造表达式树时,我必须使用调用外部方法的节点来获取表达式然后可以继续评估的值。 这些方法以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); }

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

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

When constructing an expression tree, I have to use nodes invoking external methods in order to obtain values the expression could then continue evaluation with. These methods are supplied as Func<T> and my code has no knowledge of where they originate from.

What is the most correct way of performing the mentioned invocation? I've tried something like this:

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

which works as long as the method fetched from the dictionary was created in compile-time. However, in case of Func<T> being a dynamic method obtained, for instance, by compiling another expression in runtime, this won't work out throwing

ArgumentException: Incorrect number of arguments supplied for call to method 'Int32 lambda_method(System.Runtime.CompilerServices.ExecutionScope)'

The desired effect may be achieved by wrapping the given function into one extra expression, but that seems quite hideous comparing to what it used to look like:

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); }

Also, this is hardly an extensible approach should I need to add support for types other than double and string.

I would like to know if there are better options which would work with dynamically created methods (preferably applicable to .NET 3.5).

最满意答案

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

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

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

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

which works as long as the method fetched from the dictionary was created in compile-time

No, it works as long as the method is static. For example, it also won't work if the delegate is a lambda that references something from its parent score (i.e. it's a closure).

The correct way to invoke a delegate is to use Expression.Invoke(). To get an Expression that represents your delegate, use Expression.Constant():

Expression.Invoke(Expression.Constant(method)))表达式树中的动态方法调用(dynamic method invocation in expression tree)

在构造表达式树时,我必须使用调用外部方法的节点来获取表达式然后可以继续评估的值。 这些方法以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); }

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

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

When constructing an expression tree, I have to use nodes invoking external methods in order to obtain values the expression could then continue evaluation with. These methods are supplied as Func<T> and my code has no knowledge of where they originate from.

What is the most correct way of performing the mentioned invocation? I've tried something like this:

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

which works as long as the method fetched from the dictionary was created in compile-time. However, in case of Func<T> being a dynamic method obtained, for instance, by compiling another expression in runtime, this won't work out throwing

ArgumentException: Incorrect number of arguments supplied for call to method 'Int32 lambda_method(System.Runtime.CompilerServices.ExecutionScope)'

The desired effect may be achieved by wrapping the given function into one extra expression, but that seems quite hideous comparing to what it used to look like:

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); }

Also, this is hardly an extensible approach should I need to add support for types other than double and string.

I would like to know if there are better options which would work with dynamically created methods (preferably applicable to .NET 3.5).

最满意答案

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

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

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

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

which works as long as the method fetched from the dictionary was created in compile-time

No, it works as long as the method is static. For example, it also won't work if the delegate is a lambda that references something from its parent score (i.e. it's a closure).

The correct way to invoke a delegate is to use Expression.Invoke(). To get an Expression that represents your delegate, use Expression.Constant():

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