1

나는이 테스트를 통과 할 :이 제대로 작동하려면 스택 걸어 lagacy 코드를 할 필요가있다Expression.Lambda를 모든 소유자 유형에 연결하는 방법은 무엇입니까?

[Test] 
public void LambdaTest() 
{ 
    var m = Expression.Lambda(typeof(Func<int>), Expression.Constant(0)).Compile(); 
    Assert.That(m.Method.DeclaringType, Is.Not.Null); 
} 

. 가장 간단한 방법은 무엇입니까?

나는 가장 휴대하기 쉬운 방법을 선호합니다.

+0

런타임에 새 유형을 생성하는 옵션이 있습니까? –

+0

@ YacoubMassad 예.하지만 가장 휴대 가능한 방법을 선호합니다. – Vlad

답변

3

런타임에 새 유형을 작성한 다음 표현식을 해당 유형의 메소드로 컴파일 할 수 있습니다.

런타임에 새 어셈블리와 새 모듈을 만들어야합니다. 생성 한 후에는 원하는만큼 많은 유형을 생성 할 수 있습니다. 여기에 조립 모듈 생성하는 코드 샘플입니다 :

var typeBuilder = moduleBuilder.DefineType("MyNewType"); 

그리고 다음과 같은 새로운 방법 : 이제

var assemblyBuilder = 
    AppDomain.CurrentDomain.DefineDynamicAssembly(
     new AssemblyName {Name = "MyNewAssembly"}, 
     AssemblyBuilderAccess.Run); 

var moduleBuilder = assemblyBuilder.DefineDynamicModule("MyNewModule"); 

, 당신은이 같은 새로운 유형을 정의하는 모듈 빌더를 사용할 수 있습니다 :

var methodBuilder = 
    typeBuilder.DefineMethod(
     "MyNewMethod", 
     MethodAttributes.Public | MethodAttributes.Static, 
     typeof(int), //returns an int 
     new Type[]{}); //takes no parameters 

메서드 서명은 표현 대리자 형식과 일치해야합니다.

var type = typeBuilder.CreateType(); 

그런 다음 우리에 Delegate.CreateDelegate 방법을 사용하십시오

var expression = Expression.Lambda(typeof(Func<int>), Expression.Constant(0)); 

expression.CompileToMethod(methodBuilder); 

우리는 유형 빌더의 실제 유형을 생성합니다

다음으로, 우리는 CompileToMethod 방법을 사용하여 새로운 방법으로 표현을 컴파일 다음과 같이 새로 생성 된 정적 메서드에 대한 대리자를 만듭니다.

Func<int> func = 
    (Func<int>)Delegate.CreateDelegate(
     typeof(Func<int>), 
     type.GetMethod("MyNewMethod")); 

int value = func(); //Test 

이제 func.Method.DeclaringType은 동적으로 생성 된 유형을 반환합니다.

이 코드를 사용하면 쉽게 사용할 수있는 몇 가지 도우미 메서드를 생성 할 수 있습니다.

+0

작동 여부를 알고 계십니까?NET 코어 또는 포터블 프레임 워크? – Vlad

+0

잘 모르겠습니다. 왜 테스트하지 않습니까? –

+0

니스! 나는 그것에 대해서 생각조차하지 않았다. 확실히 이것을 구현하려고합니다! – MichaelDotKnox

1

좋아, 내가 직접 발견했지만 .NET Framework에서 작동하는 방법과이 프레임 워크가 지원하지 않을 수도 있습니다. 더 나은 (더 우아하고 이식 가능한) 솔루션을 갖고 있다면 답을 자유롭게 게시하십시오.

열쇠는 CompileToMethodLambda 표현을 사용하는 것입니다.

[Test] 
public void LambdaTest2() 
{ 
    var asm = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("test"), AssemblyBuilderAccess.Run); 
    var masm = asm.DefineDynamicModule("main"); 

    var type = masm.DefineType("TestType"); 
    var mb = type.DefineMethod("TestMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(int), new Type[0]); 

    // your lambda 
    ConstantExpression expressionTree = Expression.Constant(0); 
    Expression.Lambda(typeof(Func<int>), expressionTree).CompileToMethod(mb); 

    var m = (Func<int>)Delegate.CreateDelegate(typeof(Func<int>), type.CreateType().GetMethod("TestMethod")); 

    Assert.That(m.Method.DeclaringType, Is.Not.Null); 

    // you can create another in the same module but with another type (because type can't be changed) 
    var type2 = masm.DefineType("TestType2"); 
    var mb2 = type2.DefineMethod("TestMethod2", MethodAttributes.Public | MethodAttributes.Static, typeof(int), new Type[0]); 

    // your lambda 2 
    ConstantExpression expresisonTree2 = Expression.Constant(1); 
    Expression.Lambda(typeof(Func<int>), expresisonTree2).CompileToMethod(mb2); 

    var m2 = (Func<int>)Delegate.CreateDelegate(typeof(Func<int>), type2.CreateType().GetMethod("TestMethod2")); 

    Assert.That(m2.Method.DeclaringType, Is.Not.Null); 

    // check correctness 
    Assert.That(m(), Is.EqualTo(0)); 
    Assert.That(m2(), Is.EqualTo(1)); 
} 
관련 문제