람다 식을 컴파일하면 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>> 를 감쌀 수있게하는 것입니다. 중첩 된 대리자가 아닌 경우 이미이 작업을 수행 할 수 있습니다. 여기에 설명 된대로 리플렉션 중에 유용 합니다 .

Closure 객체를 올바르게 초기화하려면 어떻게해야합니까? 아니면이 Closure 객체가 거기에 있지 않게하는 방법은 무엇입니까?

수락 된 답변

표시되는 Closure 유형은 구현 세부 사항입니다. MSDN 은 그것에 대해 매우 명시 적입니다.

이 API는 .NET Framework 인프라를 지원하며 사용자 코드에서 직접 사용할 수 없습니다. 동적으로 생성 된 메서드의 런타임 상태를 나타냅니다.

표현식 트리는 상태를 가질 수 있습니다.

클로저 인스턴스에는 람다식이 잘 닫히는 모든 비 문자 상수가 포함됩니다. 또한 표현식 트리에서 중첩 된 람다에 대한 대리자 체인을 포함 할 수 있습니다.

이를 달성하기 위해 표현 트리 컴파일러는 귀여운 트릭을 사용합니다. 정적 인 DynamicMethod 사용하여 메모리 코드를 생성합니다. 그러나 그들은 첫 번째 논점에 대해 닫힌 대리인을 만들고 있습니다. 즉, CLR이 정적 메서드의 첫 번째 인수로 대리인의 대상 필드를 전달하므로 필요하지 않습니다. Closure 인수를 효과적으로 감추고 있습니다.

문제의 해결 방법은 간단합니다. 리플렉션을 사용하는 경우 Delegate.DynamicInvoke 를 사용하거나 표현식 트리의 컨텍스트에서 Expression.Invoke 를 사용하여 메서드를 호출하거나 대리자를 호출하지 마십시오.



아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.