3

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

svick
  • 236,525
  • 50
  • 385
  • 514
  • What about arguments? Do these methods take any arguments, or not? – nightwatch Jan 04 '14 at 08:48
  • @nightwatch No arguments, dictionary is guaranteed to contain only `Func` delegates with T being either `double` or `string` (the list of these types may well require extension in future). – Denis Aldoshin Jan 04 '14 at 08:53
  • I don't know linq expressions that well, sorry. But what you're doing looks like a dynamic invocation with method names being resolved at runtime. Maybe you could just use a dynamic object as an interface to your external functions? – nightwatch Jan 04 '14 at 10:07

1 Answers1

2

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)))
svick
  • 236,525
  • 50
  • 385
  • 514
  • Well, actually it works for non-static methods (in this case an overloaded version must be used with `Expression.Constant(method.Target)` as the 1st argument, by bad). The problem is, the dynamic methods do not have a `Target`. Your answer is just what I needed, thanks! – Denis Aldoshin Jan 05 '14 at 17:02