2013-08-12 30 views
5

是否可以編寫通用的CIL指令,它將任何類型(值和引用)的實例轉換爲System.String? 特別是,我對Mono.Cecil代碼感興趣,它將這些指令注入方法中。是否有一個通用的CIL代碼將任何類型的實例轉換爲字符串?

分析我想出了這些Mono.Cecil能泛型方法調用: (它應該給我個方法參數字符串轉換)

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)); 

然而,當我調試從得到一個異常注入方法「JIT編譯器遇到內部限制」。

+1

在這種情況下,PEVerify可以非常有用,因爲它可以告訴你代碼有什麼特定的錯誤。 – svick

回答

8

編輯:

同樣重要:請注意,我用的typeof(object).GetMethod(...),不typeof(T).GetMethod(...) - 你行argument_type.GetType().GetMethod("ToString");看起來很懷疑IMO。


我懷疑的問題是,你加載本地/參數,而不是地址的本地/說法 - 立即顯示什麼前行Constrained需要這樣才能正確執行靜態調用實現;對於虛擬呼叫的實現,它可以簡單地將其解引用以得到實際的參考。

除此之外:Constrained應該可以正常工作 - 請參閱下文(特別注意Ldarga_S)。當然,另一種選擇是使用Box,但這會產生更多開銷。 Constrained理想的在任意類型上調用ToString的方法。

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

這正是我所做的:Ldarg而不是Ldarga。 – zagrobelski

+0

@zagrobelski不是一個糟糕的猜測; p –

相關問題