編譯lambda表達式會導致委託使用Closure參數

c# expression-trees lambda

當我使用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<object>>包裝例如Func<Action<SomeObject>> Func<Action<object>> 。我已經可以為非嵌套代理執行此操作。這在反射過程中非常有用, 如此處所述

我應該如何正確初始化此Closure對象,或者如何防止它出現在那裡?

一般承認的答案

您看到的Closure類型是一個實現細節。 MSDN非常清楚:

此API支持.NET Framework基礎結構,不能直接在您的代碼中使用。表示動態生成的方法的運行時狀態。

表達式樹可以具有狀態。

Closure實例將包含lambda表達式關閉的所有非文字常量。它還可以包含表達式樹中嵌套lambda的委託鏈。

為實現這一點,表達式樹編譯器使用了一個可愛的小技巧。它使用DynamicMethod生成內存代碼,根據定義靜態。然而,他們正在創建一個“ 關於其第一個論點”的代表。這意味著CLR將傳遞委託的目標字段作為靜態方法的第一個參數,因此您不必這樣做。有效地隱藏了您的Closure參數。

解決問題的方法很簡單,不要嘗試調用方法,調用委託,或者在使用反射時使用Delegate.DynamicInvoke ,或者在表達式樹的上下文中使用Expression.Invoke



許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因