1

와 싱글에서 인스턴스 메서드를 호출하는 방법 :.. :(작동 런타임을 불안정 수 있고, 내가 왜 잘 모릅니다 ... 나는 지역 추가나는 예외가되는 발광

도와주세요,하지만 여전히 작동하지하시기 바랍니다

메소드 (REF000001)를 동적으로 생성 할 :

public static int REF000001(int REF000002, object REF000003, DateTime REF000004) 
    { 
     return (int)typeof(REF000005).GetMethod("REF000006", new Type[] { typeof(int), typeof(object), typeof(DateTime) }).Invoke(REF000005.REF000008(), new object[] { REF000002, REF000003, REF000004 }); 
    } 

이 제가 단독에서 메소드를 호출 할 클래스이다

public class REF000005 
{ 
    private static REF000005 REF000007; 

    private REF000005() 
    { 

    } 

    public static REF000005 REF000008() 
    { 
     if (REF000007 == null) 
      REF000007 = new REF000005(); 

     return REF000007; 
    } 

    public int REF000006(int REF000009, object REF000010, DateTime REF000011) 
    { 
     return 5; 
    } 
} 
012,351. ILDASM에서 6,

반환 :

.method public hidebysig static int32 REF000001(int32 REF000002, 
              object REF000003, 
              valuetype [mscorlib]System.DateTime REF000004) cil  managed 
{ 
// Code size  118 (0x76) 
.maxstack 5 
.locals init ([0] int32 CS$1$0000, 
     [1] class [mscorlib]System.Type[] CS$0$0001, 
     [2] object[] CS$0$0002) 
IL_0000: nop 
IL_0001: ldtoken ConsoleApplication3.REF000005 
IL_0006: call  class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) 
IL_000b: ldstr  "REF000006" 
IL_0010: ldc.i4.3 
IL_0011: newarr  [mscorlib]System.Type 
IL_0016: stloc.1 
IL_0017: ldloc.1 
IL_0018: ldc.i4.0 
IL_0019: ldtoken [mscorlib]System.Int32 
IL_001e: call  class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) 
IL_0023: stelem.ref 
IL_0024: ldloc.1 
IL_0025: ldc.i4.1 
IL_0026: ldtoken [mscorlib]System.Object 
IL_002b: call  class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) 
IL_0030: stelem.ref 
IL_0031: ldloc.1 
IL_0032: ldc.i4.2 
IL_0033: ldtoken [mscorlib]System.DateTime 
IL_0038: call  class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) 
IL_003d: stelem.ref 
IL_003e: ldloc.1 
IL_003f: call  instance class [mscorlib]System.Reflection.MethodInfo [mscorlib]System.Type::GetMethod(string, 
                              class [mscorlib]System.Type[]) 
IL_0044: call  class ConsoleApplication3.REF000005 ConsoleApplication3.REF000005::REF000008() 
IL_0049: ldc.i4.3 
IL_004a: newarr  [mscorlib]System.Object 
IL_004f: stloc.2 
IL_0050: ldloc.2 
IL_0051: ldc.i4.0 
IL_0052: ldarg.0 
IL_0053: box  [mscorlib]System.Int32 
IL_0058: stelem.ref 
IL_0059: ldloc.2 
IL_005a: ldc.i4.1 
IL_005b: ldarg.1 
IL_005c: stelem.ref 
IL_005d: ldloc.2 
IL_005e: ldc.i4.2 
IL_005f: ldarg.2 
IL_0060: box  [mscorlib]System.DateTime 
IL_0065: stelem.ref 
IL_0066: ldloc.2 
IL_0067: callvirt instance object [mscorlib]System.Reflection.MethodBase::Invoke(object, 
                        object[]) 
IL_006c: unbox.any [mscorlib]System.Int32 
IL_0071: stloc.0 
IL_0072: br.s  IL_0074 
IL_0074: ldloc.0 
IL_0075: ret 
} // end of method Program::REF000001 

당신이 복사하는 방법 및 당신이 만드는 사람 사이에 차이가 있습니다 런타임

static DynamicMethod Method1A() 
    { 
     DynamicMethod method1 = new DynamicMethod("Dodaj", typeof(void), new Type[] { typeof(int), typeof(object), typeof(DateTime) }); 
     ILGenerator il = method1.GetILGenerator(); 

     Label target = il.DefineLabel(); 

     var tps = il.DeclareLocal(typeof(Type[])); 
     var obs = il.DeclareLocal(typeof(object[])); 

     il.Emit(OpCodes.Ldtoken, typeof(REF000005)); 
     il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", new Type[1] { typeof(RuntimeTypeHandle) })); 
     il.Emit(OpCodes.Ldstr, "REF000006"); 

     il.Emit(OpCodes.Ldc_I4_3); 
     il.Emit(OpCodes.Newarr, typeof(Type)); 
     il.Emit(OpCodes.Stloc, tps); 
     il.Emit(OpCodes.Ldloc, tps); 
     il.Emit(OpCodes.Ldc_I4_0); 
     il.Emit(OpCodes.Ldtoken, typeof(Int32)); 
     il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", new Type[1] { typeof(RuntimeTypeHandle) })); 
     il.Emit(OpCodes.Stelem_Ref); 
     il.Emit(OpCodes.Ldloc, tps); 
     il.Emit(OpCodes.Ldc_I4_1); 
     il.Emit(OpCodes.Ldtoken, typeof(Object)); 
     il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", new Type[1] { typeof(RuntimeTypeHandle) })); 
     il.Emit(OpCodes.Stelem_Ref); 
     il.Emit(OpCodes.Ldloc, tps); 
     il.Emit(OpCodes.Ldc_I4_2); 
     il.Emit(OpCodes.Ldtoken, typeof(DateTime)); 
     il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", new Type[1] { typeof(RuntimeTypeHandle) })); 
     il.Emit(OpCodes.Stelem_Ref); 
     il.Emit(OpCodes.Ldloc, tps); 

     il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetMethod", new Type[2] { typeof(string), typeof(Type[]) })); 
     il.Emit(OpCodes.Call, typeof(REF000005).GetMethod("REF000008")); 

     il.Emit(OpCodes.Ldc_I4_3); 
     il.Emit(OpCodes.Newarr, typeof(object)); 
     il.Emit(OpCodes.Stloc, obs); 
     il.Emit(OpCodes.Ldloc, obs); 
     il.Emit(OpCodes.Ldc_I4_0); 
     il.Emit(OpCodes.Ldarg, 0); 
     il.Emit(OpCodes.Box, typeof(Int32)); 
     il.Emit(OpCodes.Stelem_Ref); 
     il.Emit(OpCodes.Ldloc, obs); 
     il.Emit(OpCodes.Ldc_I4_1); 
     il.Emit(OpCodes.Ldarg, 1); 
     //il.Emit(OpCodes.Box, typeof(object)); 
     il.Emit(OpCodes.Stelem_Ref); 
     il.Emit(OpCodes.Ldloc, obs); 
     il.Emit(OpCodes.Ldc_I4_2); 
     il.Emit(OpCodes.Ldarg, 2); 
     il.Emit(OpCodes.Box, typeof(DateTime)); 
     il.Emit(OpCodes.Stelem_Ref); 
     il.Emit(OpCodes.Ldloc, obs); 
     il.Emit(OpCodes.Box, typeof(object[])); 
     il.Emit(OpCodes.Callvirt, typeof(MethodBase).GetMethod("Invoke", new Type[2] { typeof(object), typeof(object[]) })); 
     il.Emit(OpCodes.Unbox_Any, typeof(Int32)); 
     il.Emit(OpCodes.Ret); 
     return method1; 
    } 
+0

[로컬 변수 선언]을 잊어 버린 것 같습니다 (http://msdn.microsoft.com/en-us/library/y1xffef4.aspx). – svick

+0

로컬을 추가하고 코드를 변경했지만 여전히 작동하지 않습니다. 도와 주실 수 있으시겠습니까? – user2807597

답변

3

을 불안정하게 할 수 IL 발생 던져 예외 동작에 내 코드 : 전자는 int이고 후자는 void입니다. 정확하게 코드가 작동하지 않는 이유는 무엇입니까? void 메서드에서 돌아 왔을 때 스택은 비어 있어야합니다. 비 void 메서드에서 돌아 왔을 때 스택은 반환 할 값을 포함해야합니다.

이런 종류의 문제를 확인하는 가장 좋은 방법은 동적 어셈블리의 형식으로 메서드를 만들고 해당 어셈블리를 디스크에 저장 한 다음 PEVerify를 실행하는 것입니다.

수정하려면 작성중인 메소드의 반환 유형을 int으로 변경할 수 있습니다. 또 다른 옵션은 방법 void을 유지하는 것입니다. 그러나바로 전에 스택에있는 요소 인 pop을 유지하십시오.


실제로 나는 당신이 여기서 성취하려는 것을 이해하지 못합니다. C# 메서드는 이미 필요한 것을 정확하게 수행하므로 Reflection.Emit을 사용할 필요가 없습니다. 리플렉션 사용의 성능 저하를 피하기 위해 Reflection.Emit을 사용하려면 일리노이의 리플렉션을 사용할 수 없습니다.

+0

감사합니다, peverify는 대단합니다 :) – user2807597

+0

@ user2807597 내 asnwer가 실제로 귀하의 질문에 답변했다고 생각한다면 [수락해야합니다] (http://meta.stackexchange.com/a/5235/130186). – svick