2014-10-21 5 views
1

컴파일 타임에 알 수없는 유형의 생성자를 호출하는 다양한 방법을 비교하려고합니다. 4 가지 메서드가 있습니다. 즉, (타이밍 비교를 위해) 생성자를 직접 호출하고, ConstructorInfo.Invoke를 호출하고, Expression.Lambda.Compile을 호출하고, Activator.Create를 호출하는 4 가지 메서드가 있습니다. 내가 작동하지 못하는 것은 DynamicMethod를 사용하고 있습니다. 여기에 내 코드의 작은 샘플은 다음과 같습니다생성자를 호출하는 DynamicMethod 만들기

public struct Foo { 
    private int _val; 
    public Foo(int val) { 
     _val = val; 
    } 
    public override string ToString() { 
     return _val.ToString(); 
    } 
} 

static void Main(string[] args) { 
    var ctorInfo = typeof(Foo).GetConstructor(new[] { typeof(int) }); 
    var ctorDynamic = new DynamicMethod("CreateFoo", 
      typeof (Foo), new[] {typeof (int)}); 

    var ilGenerator = ctorDynamic.GetILGenerator(); 
    // Load the int input parameter onto the stack 
    ilGenerator.Emit(OpCodes.Ldloc_0); 
    // Call the constructor 
    ilGenerator.Emit(OpCodes.Call, ctorInfo); 
    // Return the result of calling the constructor 
    ilGenerator.Emit(OpCodes.Ret); 

    // Create a delegate for calling the constructor 
    var ctorInvoker = (Func<int, Foo>)ctorDynamic.CreateDelegate(
         typeof(Func<int, Foo>)); 

    // Call the constructor 
    var foo = ctorInvoker(5); 
} 

내가 마지막 줄에 생성자의 대리자를 호출 할 때, 나는 말한다 대한 VerificationException 얻을 "작업 런타임을 불안정하게 할 수 있습니다." 하나 이상의 opcode가 누락되었지만 어느 opcode가 있는지 모릅니다. 누구든지 DynamicMethod를 사용하여 적절한 방법을 알고 있습니까?

답변

3

일리노이를 쓰려고 할 때 가장 좋은 방법은 대개 동일한 C# 코드를 작성한 다음 생성 된 IL을 보는 것입니다.

그래서, 당신은 같은 방법을 쓰기 :

static Foo f(int i) 
{ 
    return new Foo(i); 
} 

을 그리고 IL은 다음과 같이 표시됩니다

  1. 는로드하려면 :

    ldarg.0 
    newobj  Foo..ctor 
    ret 
    

    이 당신이 만든 두 개의 오류를 표시 메서드 인수를 사용하는 경우 ldarg, ldloc은 로컬 변수 전용입니다.

  2. newobj을 사용하여 생성자를 호출해야합니다. 생성자는 Foo - 재귀 메서드처럼 작동하지 않습니다.

이러한 오류를 수정하면 코드가 작동합니다.

+0

호기심에서 벗어나서 MSIL을 어떻게 보았습니까? VS2013과 함께 제공되는 ildasm이라는 도구가 있지만 작동해야하는 * .re 파일을 찾을 수 없음을 알았습니다. –

+0

newobj는 작동하지만 값 유형의 경우 정상이 아니므로 컴파일러에서 위의 내용을 볼 수 없습니다. 문서에서 : "값 유형은 일반적으로 newobj를 사용하여 생성되는 것이 아니라 일반적으로 인수 또는 로컬 변수로 newarr (0부터 1 차원 배열까지) 또는 객체 필드로 할당됩니다. Initobj를 사용하여 초기화되지만 newobj 명령을 사용하여 스택에 값 유형의 새 인스턴스를 만들고이를 인수로 전달하거나 로컬에 저장하는 등의 작업을 수행 할 수 있습니다. " –

+0

@ user960115 그래, ildasm이 하나의 옵션입니다. 일반 .Net .DLL 및 .EXE에서 작동합니다. – svick

관련 문제