2013-08-12 13 views
5

Ist es möglich, generische CIL-Anweisungen zu schreiben, die Instanzen eines beliebigen Typs (Wert und Referenz) in System.String konvertieren? Insbesondere interessiert mich Mono.Cecil Code, der diese Anweisungen in eine Methode injizieren wird.Gibt es einen generischen CIL-Code, um eine beliebige Typinstanz in eine Zeichenfolge zu konvertieren?

eine generische Methode analysiert ich mit dieser Mono.Cecil kam ruft: (es soll die i-te Methode Parameter Zeichenfolge konvertieren)

System.Reflection.MethodInfo to_string_method_info = typeof(System.Object).GetMethod("ToString"); 
Mono.Cecil.MethodReference to_string_reference = injectible_assembly.MainModule.Import(to_string_method_info); 

Mono.Cecil.TypeReference argument_type = method_definition.Parameters[ i ].ParameterType; 
method_definition.Body.Instructions.Add(processor.Create(Mono.Cecil.Cil.OpCodes.Constrained, argument_type)); 
method_definition.Body.Instructions.Add(processor.Create(Mono.Cecil.Cil.OpCodes.Callvirt, to_string_reference)); 

Wenn ich jedoch eine Ausnahme von der Get Debuggen injected-Methode, dass der "JIT-Compiler auf interne Begrenzung stieß".

+1

In solchen Fällen kann PEVerify sehr nützlich sein, weil es Ihnen sagen kann, welchen spezifischen Fehler Ihr Code hat. – svick

Antwort

8

Edit:

Wichtig: beachten Sie, dass ich typeof(object).GetMethod(...) verwende, nicht typeof(T).GetMethod(...) - Ihre Linie argument_type.GetType().GetMethod("ToString"); sieht sehr vermuten, IMO.


Ich vermute, dass das Problem ist, dass Sie ein lokales/Argument laden, anstatt die Adresse eines lokalen/Argument - in der Linie unmittelbar vor Gezeigten. Constrained benötigt dies, damit es die statische Aufrufimplementierung korrekt durchführen kann; Für die Implementierung mit virtuellem Aufruf kann dies einfach deneferenziert werden, um die tatsächliche Referenz zu erhalten.

Ansonsten: Constrained sollte gut funktionieren - siehe unten (beachten Sie insbesondere die Ldarga_S). Natürlich ist eine andere Option, Box zu verwenden, aber das wird mehr Overhead haben. Constrained ist die ideal Art des Aufrufs ToString auf einen beliebigen Typ.

using System; 
using System.Reflection.Emit; 

public class RefTypeNoImpl { } 
public class RefTypeImpl { public override string ToString() { return "foo"; } } 
public struct ValTypeNoImpl { } 
public struct ValTypeImpl { public override string ToString() { return "bar"; } } 

static class Program 
{ 
    static void Main() 
    { 
     Test<RefTypeNoImpl>(); 
     Test<RefTypeImpl>(); 
     Test<ValTypeNoImpl>(); 
     Test<ValTypeImpl>(); 
    } 


    static void Test<T>() where T : new() 
    { 
     var dm = new DynamicMethod("foo", typeof(string), new[] { typeof(T) }); 
     var il = dm.GetILGenerator(); 
     il.Emit(OpCodes.Ldarga_S, 0); 
     il.Emit(OpCodes.Constrained, typeof(T)); 
     il.Emit(OpCodes.Callvirt, typeof(object).GetMethod("ToString")); 
     il.Emit(OpCodes.Ret); 
     var method = (Func<T, string>)dm.CreateDelegate(typeof(Func<T, string>)); 
     Console.WriteLine(method(new T())); 
    } 
} 
+0

Genau das habe ich gemacht: Ldarg statt Ldarga. – zagrobelski

+0

@zagrobelski keine schlechte Schätzung; p –