2010-11-10 22 views
8

Als ein bisschen eine Neuheit, ich versuche zu sehen, wie anders die IL von Lightweight-Code zur Laufzeit erstellt vs Code vom VS-Compiler erzeugt, als ich festgestellt habe, dass VS-Code neigt dazu, mit einem anderen Leistungsprofil zu laufen Dinge wie Guss.Wie erhalte ich ein IL-Bytearray von einer DynamicMethod?

Also schrieb ich den folgenden Code ::

Func<object,string> vs = x=>(string)x; 
Expression<Func<object,string>> exp = x=>(string)x; 
var compiled = exp.Compile(); 
Array.ForEach(vs.Method.GetMethodBody().GetILAsByteArray(),Console.WriteLine); 
Array.ForEach(compiled.Method.GetMethodBody().GetILAsByteArray(),Console.WriteLine); 

Leider ist dies löst eine Ausnahme als GetMethodBody offenbar eine illegale Operation Code durch Expression Bäume erzeugt wird. Wie kann ich in einer Bibliotheksart (d. H. Nicht mit einem externen Tool, es sei denn, das Tool verfügt über eine API) den Code anzeigen, der mit Hilfe von Lightweight Codegen generiert wurde?

Bearbeiten: Der Fehler tritt in Zeile 5, kompilierte.Method.GetMethodBody() löst die Ausnahme.

Edit2: Kann jemand die lokalen Variablen, die in der Methode deklariert werden, wiederherstellen? Oder gibt es keine Möglichkeit, GetVariables?

+0

Welche Zeile wirft die Ausnahme? Kannst du das erste Array.ForEach auskommentieren und sehen, ob das funktioniert?Ich vermute, dass der erste Aufruf von GetMethodBody() fehlschlägt, weil dieser Ausdruck nicht nach IL kompiliert wurde. Ich sehe keinen Grund, warum der zweite Anruf fehlschlagen sollte. – cdhowie

+0

Interessante Frage. Beim GetMethodBody-Aufruf erhalte ich eine InvalidOperationException ("Operation ist wegen des aktuellen Status des Objekts nicht gültig"). Ich bin mir nicht sicher, wie das Leben als CachedAnonymousDelegate vs Expression Ihr Verhalten als Func beeinflussen würde. Ich werde weiter daran arbeiten. – Sorax

+0

Die ausgewählte Antwort sollte umgeschaltet werden, da sie nicht alle Fälle abdeckt und unnötig komplex ist. Bitte lesen Sie [diese Antwort] (http://stackoverflow.com/a/35711507/521757). – jnm2

Antwort

16

Ja, funktioniert nicht, die Methode wird von Reflection.Emit generiert. Die IL wird im ILGenerator des MethodBuilder gespeichert. Du kannst es ausgraben, aber du musst ziemlich verzweifelt sein. Um zu den internen und privaten Mitgliedern zu gelangen, bedarf es einer Reflexion. Das funktionierte auf .NET 3.5SP1:

using System.Linq.Expressions; 
using System.Reflection; 
using System.Reflection.Emit; 
... 

     var mtype = compiled.Method.GetType(); 
     var fiOwner = mtype.GetField("m_owner", BindingFlags.Instance | BindingFlags.NonPublic); 
     var dynMethod = fiOwner.GetValue(compiled.Method) as DynamicMethod; 
     var ilgen = dynMethod.GetILGenerator(); 
     var fiBytes = ilgen.GetType().GetField("m_ILStream", BindingFlags.Instance | BindingFlags.NonPublic); 
     var fiLength = ilgen.GetType().GetField("m_length", BindingFlags.Instance | BindingFlags.NonPublic); 
     byte[] il = fiBytes.GetValue(ilgen) as byte[]; 
     int cnt = (int)fiLength.GetValue(ilgen); 
     // Dump <cnt> bytes from <il> 
     //... 

On 4.0 .NET Sie ilgen.GetType verwenden() BaseType.GetField (...), weil der IL-Generator geändert wurde, DynamicILGenerator, abgeleitet aus. ILGenerator.

+0

Yuck! Vielen Dank! –

+0

Oh, verdammt, das ist hässlich. Gute Arbeit ... es ist eine Schande, dass der Code nicht schöner sein kann. :( – cdhowie

+0

Probieren Sie es einfach, Dies scheint nicht in .NET zu funktionieren 4. es sagt mir, dass fiBytes null ist :( –

0

Basiert weg von Hans Passant Arbeit konnte ich ein wenig tiefer graben, erscheint eine Methode zu sein, dass Sie anrufen sollte, genannt BakeByteArray so die folgenden Werke ::

var dynMethod = fiOwner.GetValue(compiled.Method) as DynamicMethod; 
var ilgen =dynamicMethod.GetILGenerator(); 
byte[] il = ilgen.GetType().GetMethod("BakeByteArray", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(ilgen, null) as byte[]; 

Dies hilft sicherlich, aber ich immer noch habe keine Möglichkeit, VariableInfo's gerade noch zu lösen, was etwas ist, das in meiner Arbeit helfen würde.

+2

Sie backen es zweimal. Nicht sicher, ob es verbrannt wird, wahrscheinlich nicht. –

+0

Ich bin mir nicht sicher, aber dieser Code ist völlig nutzlos, da ich das, was ich realistischerweise benutze, nicht zerlegen kann, da ich die Metadaten nicht zu etwas Nützlichem lösen kann, da das Modul, das auf der Sache aufgelistet ist, wertlos erscheint . –

0

Die aktuellen hier Lösungen sind nicht die aktuelle Situation in .NET 4 sehr gut Adressierung. Sie können entweder DynamicILInfo oder ILGenerator verwenden, um die dynamische Methode zu erstellen, aber die hier aufgelisteten Lösungen funktionieren nicht mit DynamicILInfo dynamischen Methoden an allen.

Ob Sie die DynamicILInfo Verfahren zur Erzeugung von IL oder die ILGenerator Methode verwenden, endet der IL-Bytecode in DynamicMethod.m_resolver.m_code auf. Sie müssen nicht beide Methoden überprüfen und es ist eine weniger komplexe Lösung.

Dies ist die Version, die Sie verwenden sollten:

public static byte[] GetILBytes(DynamicMethod dynamicMethod) 
{ 
    var resolver = typeof(DynamicMethod).GetField("m_resolver", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(dynamicMethod); 
    if (resolver == null) throw new ArgumentException("The dynamic method's IL has not been finalized."); 
    return (byte[])resolver.GetType().GetField("m_code", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(resolver); 
} 

See this answer für mehr Hilfsmethoden und eine Lösung für die Dynamic Token Auflösung Problem.

Verwandte Themen