2017-07-26 185 views
2

我是ILGenerator的新手,對我來說如此光禿禿,直接指向我可能有所幫助的任何答案。謝謝。ILGenerator實例化對象和調用實例方法

我想構造一個泛型類型的實例並調用該實例上的方法。然後返回該方法的結果。

var genericType = typeof(GenericType<>).MakeGenericType(typeof(TOutput)); 
il.DeclareLocal(genericType); 
var instanceMethod = genericType.GetMethod("MethodName", new Type[0]); 
il.Emit(OpCodes.Call, instanceMethod); 
il.Emit(OpCodes.Ret); 

我不斷收到'System.InvalidProgramExecution'異常。

GenericType類看起來像這樣

public class GenericType<T> 
{ 
    public T MethodName() 
    { 
     ... 
    } 
} 
+1

一個簡單的是找出正確的IL要求是寫你想要做什麼的C#代碼,編譯在釋放模式,然後使用ILDASM來查看IL。 –

+2

您必須將目標對象的引用推入堆棧。 – whymatter

回答

0

試試這個代碼:

var il = mbuilder.GetILGenerator(); 
var genericType = typeof(GenericType<>).MakeGenericType(typeof(TOutput)); 
il.Emit(OpCodes.Newobj, genericType.GetConstructor(Type.EmptyTypes)); 
il.EmitCall(OpCodes.Callvirt, genericType.GetMethod("MethodName", Type.EmptyTypes), null); 
il.Emit(OpCodes.Ret); 
+0

所以我們可以說我想將一個本地參數傳遞給方法「MethodName」。並且該局部變量的範圍是生成IL的方法。局部變量被命名爲「myLocal」,其範圍與genericType相同。 – Mike

+0

@Mike你可以更新一個問題或者(甚至更好)創建一個新問題? –

+0

這裏是新的問題。感謝您的專業知識。我正在完成解決方案並查看生成的IL代碼,但這可能會更快。 https://stackoverflow.com/questions/45341097/ilgenerator-call-instance-method-with-parameter – Mike

0

一個簡單的方法來找出IL需要發出一個特定的功能是寫你想要的代碼手動生成,然後使用ILDASM來查看由編譯器創建的IL。

下面是一個例子...

C#方法重複...

public static TOutput DoWork() 
{ 
    var generic = new GenericType<TOutput>(); 
    var ret = generic.MethodName(); 
    return ret; 
} 

生成的IL ...

.method public hidebysig static class App.TOutput 
DoWork() cil managed 
{ 
    // Code size  15 (0xf) 
    .maxstack 1 
    .locals init ([0] class App.GenericType`1<class App.TOutput> generic, 
      [1] class App.TOutput 'ret') 
    IL_0000: newobj  instance void class App.GenericType`1<class App.TOutput>::.ctor() 
    IL_0005: stloc.0 
    IL_0006: ldloc.0 
    IL_0007: callvirt instance !0 class App.GenericType`1<class App.TOutput>::MethodName() 
    IL_000c: stloc.1 
    IL_000d: ldloc.1 
    IL_000e: ret 
} // end of method Program::DoWork 

關於如何實施例發射並調用這個IL ...

var retType = typeof(TOutput); 
var type = typeof(GenericType<>); 
var genericType = type.MakeGenericType(retType); 
var constructor = genericType.GetConstructor(Type.EmptyTypes); 
var methodDef = genericType.GetMethod("MethodName", Type.EmptyTypes); 

var newMethod = new DynamicMethod("MyMethod", retType, Type.EmptyTypes); 
var generator = newMethod.GetILGenerator(); 
generator.DeclareLocal(genericType); 
generator.DeclareLocal(retType); 
generator.Emit(OpCodes.Newobj, constructor); 
generator.Emit(OpCodes.Stloc_0); 
generator.Emit(OpCodes.Ldloc_0); 
generator.EmitCall(OpCodes.Callvirt, methodDef, null); 
generator.Emit(OpCodes.Stloc_1); 
generator.Emit(OpCodes.Ldloc_1); 
generator.Emit(OpCodes.Ret); 

var ret = newMethod.Invoke(null, null); 
Console.WriteLine(ret); // App.TOutput 

支持類...

public class GenericType<T> where T : new() 
{ 
    public T MethodName() 
    { 
     return new T(); 
    } 
} 
public class TOutput 
{ 
}