Gdy używam Expression.Lambda(...).Compile()
w celu utworzenia delegata z drzewa wyrażeń, wynikiem jest delegat, którego pierwszym argumentem jest Closure
.Kompilowanie wyrażenia lambda powoduje delegowanie z argumentem zamknięcia
public static Func<T, T, T> CreateTest<T>()
{
ParameterExpression a = Expression.Parameter(typeof(T));
ParameterExpression b = Expression.Parameter(typeof(T));
Expression addition = Expression.Add(a, b);
return (Func<T, T, T>)Expression.Lambda(addition, a, b).Compile();
}
...
// 'addition' equals
// Int32 lambda_method(
// System.Runtime.CompilerServices.Closure,
// Int32,
// Int32)
Func<int, int, int> addition = DelegateHelper.CreateTest<int>();
int result = addition(5, 5);
mogę łatwo wywołać delegata za pomocą kodu zwykłego bez przepuszczania Closure
obiekt, ale skąd ten Closure
pochodzi?
Jak mogę dynamicznie wywoływać tego delegata?
// The following does not work.
// Exception: MethodInfo must be a runtime MethodInfo object.
MethodInfo additionMethod = addition.Method;
int result = (int)additionMethod.Invoke(null, new object[] { 5, 5 });
Korzystanie z drzew wyrażeń wygląda tak, jakbym musiał minąć obiekt Closure
.
PropertyInfo methodProperty
= typeof(Delegate).GetProperty("Method", typeof(MethodInfo));
MemberExpression getDelegateMethod
= Expression.Property(Expression.Constant(addition), methodProperty);
Func<MethodInfo> getMethodInfo
= (Func<MethodInfo>)Expression.Lambda(getDelegateMethod).Compile();
// Incorrect number of arguments supplied for call to method
// 'Int32 lambda_method(System.Runtime.CompilerServices.Closure, Int32, Int32)'
Expression call
= Expression.Call(
getMethodInfo(),
Expression.Constant(5), Expression.Constant(5));
Jest to uproszczony przykład, który nie ma sensu sam w sobie. To, co faktycznie próbuję osiągnąć, to móc owijać, np. Func<Action<SomeObject>>
z Func<Action<object>>
. Mogę już to zrobić dla nie zagnieżdżonych delegatów. Jest to przydatne podczas refleksji, as discussed here.
Jak poprawnie zainicjować ten obiekt Closure
lub jak zapobiec jego występowaniu?
Czy możesz podać krótki, ale * kompletny * przykład? Nie jest tak naprawdę oczywiste, jaki jest problem. –
@JonSkeet: Zrobię co w mojej mocy, problem polega na tym, że ogólny przykład jest dość złożony. Próbuję wywoływać rekurencyjnie wcześniej skompilowanego delegata. Podczas gdy próbuję wyodrębnić mały podzbiór problemu, [tutaj] (http://pastebin.com/53f0VqnF) można już znaleźć całą funkcję. –
Tak, skrócenie tego z pewnością pomogłoby :) –