Это должно работать:
Action<int> func = i => Console.WriteLine(i * i);
// If func is null like in your example, the GetType() call fails,
// so give it a body or use typeof if you know the type at compile time
var param = Expression.Parameter(func.GetType());
// Call the Invoke method on the delegate, which is the same as invoking() it
var callExpr = Expression.Call(param, func.GetType().GetMethod("Invoke"), Expression.Constant(5));
var lambdaExpr = Expression.Lambda<Action<Action<int>>>(callExpr, param);
var fn = lambdaExpr.Compile(); // Compile the expression tree so it can be executed
fn(func); // Prints 25
Выражения могут быть ошибкой, но помните: выражения всегда строятся из других выражений . Выражение - это дерево других выражений, которое описывает код. Вы не можете передать фактический делегат, как вы делаете в своем примере, вам нужно выражение этого делегата, говоря, что выражение ожидает параметр типа вашего делегата. Затем вы говорите, что хотите вызвать метод для этого параметра, а именно метод Invoke
, с аргументом '5'. Все остальное после этого - просто если вы хотите превратить выражение в исполняемый код, что вы, вероятно, делаете.
Я запустил это с .NET4, хотя, надеюсь, я не смешивал в .NET4 только выражения.
РЕДАКТИРОВАТЬ В ответ на комментарий PythonPower:
Я думаю, что вы хотите (не передавая делегат в качестве аргумента), можно сделать только тогда, когда сам делегат описан как выражение, например:
var arg = Expression.Parameter(typeof(int), "i");
var multiply = Expression.Multiply(arg, arg);
var writeln = Expression.Call(typeof(Console).GetMethod("WriteLine",
new[] { typeof(int) }), multiply);
var lambda = Expression.Lambda<Action<int>>(writeln, arg);
var compiled = lambda.Compile();
compiled(5); // Prints 25
Единственный другой способ, который я могу придумать, - это захват делегата, объявленного локально, в закрытии, но я не знаю, как это сделать.