Question

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

Was it helpful?

Solution

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)))
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top