2016-04-01 13 views
1

neu IL ... versuchen IL zu schaffen für:anlegen/zuordnen Objekt über C# EMIT IL

Dest CreateInstance(Source src) 
{ 
    Dest d = new Dest(); 
    d.Test = src.Test; 
    return d; 
} 

Dies ist, was ich bisher:

ConstructorInfo ctor = typeof(Dest).GetConstructors()[0]; 
DynamicMethod method = new DynamicMethod("CreateIntance", typeof(Dest), 
    new Type[] { typeof(Source) }); 
ILGenerator gen = method.GetILGenerator(); 
//gen.Emit(OpCodes.Ldarg_0);// source 
gen.Emit(OpCodes.Newobj, ctor);// new Created 
gen.Emit(OpCodes.Ret); 
CreateCtor createdCtorDelegate; 
createdCtorDelegate = (CreateCtor)method.CreateDelegate(typeof(CreateCtor)); 

dies, wie oben ausgeführt wird. .. aber wenn ich den Ldarg_0 auskommentiere, bekomme ich eine "diese Operation kann die Laufzeit instabilisieren", wenn ich versuche, den Delegierten anzurufen.

Auch, was brauche ich, um das Testmitglied zu kopieren? angenommen, es ist ein Grundtypus.

Danke!

EDIT:

Quelle und Dest und nur einfache POCOs.

public class Source 
{ 
    public string S1 { get; set; } 
    public string S2 { get; set; } 
    public int I1 { get; set; } 
    public int I2 { get; set; } 
    public string S3 { get; set; } 
    public string S4 { get; set; } 
    public string S5 { get; set; } 
} 

public class Dest 
{ 
    public string S1 { get; set; } 
    public string S2 { get; set; } 
    public int I1 { get; set; } 
    public int I2 { get; set; } 
    public string S3 { get; set; } 
    public string S4 { get; set; } 
    public string S5 { get; set; } 
} 

EDIT # 2: Jetzt habe ich das ... immer noch die destabalize Fehler:

 ConstructorInfo ctor = typeof(Dest).GetConstructors()[0]; 
     DynamicMethod method = new DynamicMethod("CreateIntance", typeof(Dest), 
      new Type[] { typeof(Source) }); 
     MethodInfo miSrc = tSource.GetProperty("S1").GetGetMethod(); 
     MethodInfo miDest = tDest.GetProperty("S1").GetSetMethod(); 

     ILGenerator gen = method.GetILGenerator(); 
     gen.Emit(OpCodes.Newobj, ctor);// new Created 
     gen.Emit(OpCodes.Dup); 
     gen.Emit(OpCodes.Ldarg_1);// source 
     gen.Emit(OpCodes.Ldfld, miSrc); 
     gen.Emit(OpCodes.Stfld, miDest); 
     gen.Emit(OpCodes.Ret); 
     CreateCtor createdCtorDelegate; 
     createdCtorDelegate = (CreateCtor)method.CreateDelegate(typeof(CreateCtor)); 

     Dest dd = createdCtorDelegate(s); 

die Ausnahme, wenn ich die createdCtorDelegate nennen.

EDIT3:

ILSpy zeigt dies:

.method public hidebysig static 
    class ConsoleApplication3.Dest Test (
     class ConsoleApplication3.Source s 
    ) cil managed 
{ 
    // Method begins at RVA 0x2148 
    // Code size 26 (0x1a) 
    .maxstack 2 
    .locals init (
     [0] class ConsoleApplication3.Dest, 
     [1] class ConsoleApplication3.Dest 
    ) 

IL_0000: nop 
IL_0001: newobj instance void ConsoleApplication3.Dest::.ctor() 
IL_0006: stloc.0 
IL_0007: ldloc.0 
IL_0008: ldarg.0 
IL_0009: callvirt instance string ConsoleApplication3.Source::get_S1() 
IL_000e: callvirt instance void ConsoleApplication3.Dest::set_S1(string) 
IL_0013: nop 
IL_0014: ldloc.0 
IL_0015: stloc.1 
IL_0016: br.s IL_0018 

IL_0018: ldloc.1 
IL_0019: ret 
} // end of method Program::Test 

Also, ich habe meinen Code eingestellt:

 ConstructorInfo ctor = typeof(Dest).GetConstructors()[0]; 
     DynamicMethod method = new DynamicMethod("CreateIntance", typeof(Dest), 
      new Type[] { typeof(Source) }); 
     MethodInfo miSrc = tSource.GetProperty("S1").GetGetMethod(); 
     MethodInfo miDest = tDest.GetProperty("S1").GetSetMethod(); 

     ILGenerator gen = method.GetILGenerator(); 

     gen.Emit(OpCodes.Newobj, ctor);// new Created 
     gen.Emit(OpCodes.Stloc_0); 
     gen.Emit(OpCodes.Ldloc_0); 
     gen.Emit(OpCodes.Ldarg_0); 
     gen.Emit(OpCodes.Callvirt, miSrc); 
     gen.Emit(OpCodes.Callvirt, miDest); 
     gen.Emit(OpCodes.Ldloc_0); 
     gen.Emit(OpCodes.Stloc_1); 
     gen.Emit(OpCodes.Ldloc_1); 
     gen.Emit(OpCodes.Ret); 

     CreateCtor createdCtorDelegate; 
     createdCtorDelegate = (CreateCtor)method.CreateDelegate(typeof(CreateCtor)); 

Noch Absturz: (...

+0

Können Sie "Basistyp" angeben? Meinst du primitiven Typ oder Struktur oder ...? – thehennyy

+1

Sind Sie sich bewusst, dass die Reflexion emittiert fast obsolet ist angesichts der Tatsache, dass Ausdruck Bäume existieren? – usr

+0

Protip: Dump Sie IL in eine Datei und führen Sie PEVerify darauf aus. – leppie

Antwort

1

... but if I uncomment out the Ldarg_0 ...

Ihre Methode sollte einen Wert zurückgeben, das heißt wh Wenn die Anweisung ret erreicht wird, muss der Stapel genau ein Element enthalten. Die Anweisung newobj erstellt das neue Objekt und lädt einen Verweis darauf auf den Stapel. Wenn Sie also weitere Elemente zum Stapel hinzufügen, ohne sie zu verbrauchen, bevor Sie die ret erreichen, ist Ihr Code ungültig.

what do I need to copy the Test member over?

Der schnellste Weg gültig IL Anweisungen zu erhalten, ist eine Hochsprache zu verwenden, sowie einen Compiler und Decompiler.

IL_0000: newobj instance void Dest::.ctor() //create the new object 
IL_0005: dup        //duplicate the reference 
IL_0006: ldarg.1       //load the object to copy from 
IL_0007: ldfld object Source::Test   //load the value from the old objects field 
IL_000c: stfld object Dest::Test   //safe the value to the new objects field 
IL_0011: ret        //one reference of the new object is still on the stack 
+0

können Sie das Update im Hauptpost sehen? Ich habe Ihre Opcodes verfolgt und trotzdem den Destabaliserungsfehler erhalten. – SledgeHammer

+0

Sie verwenden Eigenschaften und nicht Felder wie ich, verwenden einen Decompiler und sehen, was mit Eigenschaften emittiert wird, sollte es "CallVirt" Opcodes mit der set/get-Methode als Operand sein. – thehennyy

+0

aktualisiert OP nach Ihren Anweisungen ... noch Absturz. – SledgeHammer

0

Ihre letzte Code ist in der Nähe zu korrigieren, müssen Sie nur die Einheimischen erklären Sie verwenden möchten: Wenn Sie dies tun, werden Sie so etwas wie dieses erhalten

ILGenerator gen = method.GetILGenerator(); 
gen.DeclareLocal(typeof(Dest)); 

Beachten Sie auch, dass die Das letzte Paar stloc.1, ldloc.1 am Ende ist nicht notwendig und ist das Ergebnis der Kompilierung Ihres Codes im Debug-Modus. Kompilieren Sie Ihren Code bei der Überprüfung von CIL immer in Release, da der Code viel kürzer und einfacher zu lesen ist.

Ihre zweite Version des Verfahrens war auch fast richtig, das Problem war hier:

gen.Emit(OpCodes.Ldarg_1);// source 

Es gibt kein „Argument 1“, da Argumentlisten von 0 (für statische Methoden gestartet wird, haben Instanzmethoden this als das Argument 0). Die Lösung ist einfach:

gen.Emit(OpCodes.Ldarg_0);// source