Когда я использую Expression.Lambda( ... ).Compile()
для создания делегата из дерева выражений, результатом является делегат, первым аргументом которого является Closure
.
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 );
Я могу легко вызвать делегата через обычный код, не передавая объект Closure
, но откуда это Closure
взято?
Как я могу вызвать этого делегата динамически?
// 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 } );
Используя деревья выражений, я должен передать объект 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 ) );
Это упрощенный пример, который сам по себе не имеет смысла. То, чего я на самом деле пытаюсь достичь, - это уметь обернуть, например. Func<Action<SomeObject>>
с Func<Action<object>>
. Я уже могу сделать это для не вложенных делегатов. Это полезно во время размышления, , как обсуждено здесь .
Как правильно инициализировать этот Closure
объект или как я могу предотвратить его появление?