2016-04-07 22 views
1

Ich arbeite an der Erstellung einer dynamischen Methode zur Laufzeit ein Objekt zu kopieren. Nehmen wir an:Reflection.Emit - IL - Aufrufmethode für Objekt

class Source 
{ 
    public List<int> L1 {get;set;} 
} 

class Dest 
{ 
    public List<int> L1 {get;set;} 
} 

Jetzt funktioniert diese Situation richtig. Ich bekomme Source.L1 und ich setze Dest.L1. Ich mache so mit dem folgenden IL:

All dies funktioniert gut ... jetzt kommt der schwierige Teil. Lässt ändern Dest zu:

class Dest 
{ 
    private List<int> _l1 = new List<int>(); 
    public List<int> L1 {get { return _l1; } } 
} 

Nun, was ich in diesem Fall tun möchte, ist anrufen Dest.L1.Clear() und dann Dest.L1.AddRange (...).

Ich kann nicht einmal die .Clear arbeiten.

Ich werde noch haben:

 generator.Emit(OpCodes.Newobj, constructor); 

     // this block is repeated 5 times for various properties 

     generator.Emit(OpCodes.Dup); 
     generator.Emit(OpCodes.Ldarg_0); 
     generator.Emit(OpCodes.Callvirt, miGetter); 
     generator.Emit(OpCodes.Callvirt, miSetter); 

     // List property will be copied here 
     // miGetter = Dest.L1.Get 
     // TODO 
     // end list property 

     generator.Emit(OpCodes.Ret); 

Wie muss ich die IL in der TODO Block einzurichten? Ich habe versucht, dup/loadArg0/call miGetter/call miClear, aber das gab mir ein ungültiges Programm.

+0

Warum wollen Sie 'Clear' anrufen? Erschaffst du nicht ein neues 'Dest'? Es wäre leer beim Bau. –

+0

Siehe die zweite Version von Dest down lower. L1 ist jetzt eine Nur-Lese-Sammlung, also kannst du den Setter nicht anrufen (naja, du kannst, aber solltest du nicht) – SledgeHammer

+0

Das ist nicht meine Frage. Wenn Sie ein neues 'Dest' erstellen, ist die' L1'-Liste leer. Sie müssen 'AddRange' aufrufen, müssen aber nicht zuerst' Clear' aufrufen. –

Antwort

3

Hier ist ein funktionierendes Beispiel mit einer Erklärung, was passiert mit dem Auswertungsstapel auf jedem Schritt:

DynamicMethod method = 
    new DynamicMethod("Test", typeof(Dest), new Type[] { typeof(Source) }); 

var generator = method.GetILGenerator(); 

var constructor = typeof(Dest).GetConstructor(Type.EmptyTypes); 

var miGetter = typeof(Source).GetProperty("L1").GetMethod; 

var miDestGetter = typeof(Dest).GetProperty("L1").GetMethod; 

var addRange = typeof(List<int>).GetMethod("AddRange"); 

var clear = typeof(List<int>).GetMethod("Clear"); 

generator.Emit(OpCodes.Newobj, constructor);//Stack: DestObject 

generator.Emit(OpCodes.Dup);//Stack: DestObject,DestObject 

generator.Emit(OpCodes.Call, miDestGetter);//Stack: DestObject,DestObject.L1 

generator.Emit(OpCodes.Dup);//Stack: DestObject,DestObject.L1,DestObject.L1 

generator.Emit(OpCodes.Call, clear);//Stack: DestObject,DestObject.L1 

generator.Emit(OpCodes.Ldarg_0);//Stack: DestObject,DestObject.L1,SourceObject 

generator.Emit(OpCodes.Call, miGetter);//Stack: DestObject,DestObject.L1,SourceObject.L1 

generator.Emit(OpCodes.Call, addRange);//Stack: DestObject 

generator.Emit(OpCodes.Ret); 

var function = (Func<Source, Dest>)method.CreateDelegate(typeof(Func<Source, Dest>)); 

Source source = new Source 
{ 
    L1 = new List<int>() { 1, 2, 3 } 
}; 

var result = function(source);