3

При построении дерева выражений я должен использовать узлы, вызывающие внешние методы, чтобы получить значения, которые выражение затем может продолжить оценку. Эти методы поставляются как 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).

+0

насчет аргументов? Используют ли эти методы какие-либо аргументы или нет? – nightwatch

+0

@nightwatch Нет аргументов, словарь гарантированно содержит только 'Func ' делегаты с T, которые являются либо 'double', либо' string' (список этих типов может потребовать расширения в будущем). –

+0

Я не знаю выражения linq, которые, извините. Но то, что вы делаете, выглядит как динамический вызов с именами методов, которые разрешаются во время выполнения. Может быть, вы можете просто использовать динамический объект в качестве интерфейса для ваших внешних функций? – nightwatch

ответ

2

, который работает до тех пор, как method извлеченной из словаря был создан в компиляции

Нет, он работает до тех пор, как method статична. Например, он также не будет работать, если делегат является лямбдой, которая ссылается на что-то из его родительского счета (т. Е. Это закрытие).

Правильный способ вызова делегата - использовать Expression.Invoke(). Чтобы получить Expression, который представляет ваш делегат, используйте Expression.Constant():

Expression.Invoke(Expression.Constant(method))) 
+0

Ну, на самом деле это работает для нестатических методов (в этом случае перегруженная версия должна использоваться с 'Expression.Constant (method.Target)' как 1-й аргумент, по плохим). Проблема заключается в том, что динамические методы не имеют «Target». Ваш ответ - это то, что мне нужно, спасибо! –