Когда я использую Expression.Lambda (...) .Compile ()
для создания делегата из дерева выражений, результат является делегатом, первым аргументом которого является Closure
.
public static Func CreateTest()
{
ParameterExpression a = Expression.Parameter( typeof( T ) );
ParameterExpression b = Expression.Parameter( typeof( T ) );
Expression addition = Expression.Add( a, b );
return (Func)Expression.Lambda( addition, a, b ).Compile();
}
...
// 'addition' equals
// Int32 lambda_method(
// System.Runtime.CompilerServices.Closure,
// Int32,
// Int32 )
Func addition = DelegateHelper.CreateTest();
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 getMethodInfo
= (Func)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
с Func
. Я уже могу сделать это для невложенных делегатов. Это полезно во время отражения, , как обсуждается здесь .
Как мне правильно инициализировать этот объект Closure
или как предотвратить его присутствие?