2010-01-15 30 views
2

HEJ所有的Silverlight 3.0 C# - 使用Methodbuilder創建一組方法,並添加具有的ILGenerator的MSIL,併發出

我有一些代碼,建立一個新的類型的運行時,它設置使用MethodBuilder GET和SET方法。 (其從網站的exampel,並感謝傢伙,那寫的,我unfortantly失去了參考文獻給他,但他是我的想法)

TypeBuilder typeBuilder = module.DefineType("MyClass", TypeAttributes.Public | TypeAttributes.Class); 

我添加一個方法到類這樣。

MethodAttributes GetSetAttr = 
     MethodAttributes.Public | 
     MethodAttributes.HideBySig; 

// Define the "get" accessor method for current private field. 
       MethodBuilder currGetPropMthdBldr = 
        typeBuilder.DefineMethod("get_value", 
               GetSetAttr, 
               typeof(string), 
               Type.EmptyTypes); 

       // Intermediate Language stuff... 
       ILGenerator currGetIL = currGetPropMthdBldr.GetILGenerator(); 
       currGetIL.Emit(OpCodes.Ldarg_0); 
       currGetIL.Emit(OpCodes.Ldfld, field); 
       currGetIL.Emit(OpCodes.Ret); 

       // Define the "set" accessor method for current private field. 
       MethodBuilder currSetPropMthdBldr = 
        typeBuilder.DefineMethod("set_value", 
               GetSetAttr, 
               null, 
               new Type[] { typeof(string) }); 

       // Again some Intermediate Language stuff... 
       ILGenerator currSetIL = currSetPropMthdBldr.GetILGenerator(); 
       currSetIL.Emit(OpCodes.Ldarg_0); 
       currSetIL.Emit(OpCodes.Ldarg_1); 
       currSetIL.Emit(OpCodes.Stfld, field); 
       currSetIL.Emit(OpCodes.Ret); 



       // Last, we must map the two methods created above to our PropertyBuilder to 
       // their corresponding behaviors, "get" and "set" respectively. 
       property.SetGetMethod(currGetPropMthdBldr); 
       property.SetSetMethod(currSetPropMthdBldr); 

它工作正常,我卻想對使用setMethod更改爲更復雜的東西,所以我寫這篇文章的測試代碼。

公共類客戶 {0}私人字符串_名稱; 公共字符串名稱 { get {return _name; } set if(string.IsNullOrEmpty(value)) {0} {0} {0}拋出new ValidationException(「請設置一個值」); } _name = value; } } public string lastname {get;組; } }

編譯然後使用Reflector來獲取MSIL。

.method public hidebysig specialname instance void set_name(string 'value') cil managed 
{ 
    .maxstack 2 
    .locals init (
     [0] bool CS$4$0000) 
    L_0000: nop 
    L_0001: ldarg.1 
    L_0002: call bool [mscorlib]System.String::IsNullOrEmpty(string) 
    L_0007: ldc.i4.0 
    L_0008: ceq 
    L_000a: stloc.0 
    L_000b: ldloc.0 
    L_000c: brtrue.s L_001a 
    L_000e: nop 
    L_000f: ldstr "Please set a value" 
    L_0014: newobj instance void [System.ComponentModel.DataAnnotations]System.ComponentModel.DataAnnotations.ValidationException::.ctor(string) 
    L_0019: throw 
    L_001a: ldarg.0 
    L_001b: ldarg.1 
    L_001c: stfld string AnnotationTest.MainPage/Customer::_name 
    L_0021: ret 
} 

因此,任務是將它實現到SET EMIT代碼中。

   currSetIL.Emit(OpCodes.Ldarg_0); 
       currSetIL.Emit(OpCodes.Ldarg_1); 
       currSetIL.Emit(OpCodes.Stfld, field); 
       currSetIL.Emit(OpCodes.Ret); 

這就是我來的短,我不能讓它的工作。它接縫,我可以「只是」複製代碼,而我的MSIL技能是有限的。以下是我的錯誤。

 currSetIL.Emit(OpCodes.Nop); //  L_0000: nop 
     currSetIL.Emit(OpCodes.Ldarg_1); // L_0001: ldarg.1 
     currSetIL.Emit(OpCodes.Call bool [mscorlib]System.String::IsNullOrEmpty(string);// call bool [mscorlib]System.String::IsNullOrEmpty(string) 

在第3行中,這些紅色下劃線給thede錯誤...

  • 布爾= 「)Expetced」
  • [mscorlib程序]系統= 「預期的」
  • :: = 「預期」
  • 和最後一個)給出 「無效 表達術語串」

我想知道爲什麼我不能使用反射器,代碼應該沒問題?要麼?

找到一個程序的方法/顯示可以在EMIT語句中使用的MSIL代碼的方法。

這只是一個例子,所以代碼將會改變,所以它不是一個解決方案來回答正確的代碼(所有的代碼都可以正常工作),而是一個更爲透徹的方式來獲得正確的MSIL C#。

Peww,一個很長的問題,我希望我在這裏擁有一切。

問候 的重新裝載

+0

重新評論; AFAIK這將是一個相當手動的翻譯。不過,嚴肅地說,我認爲你可以通過'Expression'來完成所有這些工作(特別是在新對象的情況下)。你有沒有想要達到的例子?即你可以發佈C#等價於你想要的東西嗎? – 2010-01-15 16:32:55

回答

3

currSetIL.Emit(OpCodes.Call布爾[mscorlib程序] System.String :: IsNullOrEmpty(串); //呼叫布爾[mscorlib程序] System.String :: IsNullOrEmpty(字符串)

你需要得到MethodInfo - 在這種情況下:

currSetIL.EmitCall(OpCodes.Call,typeof(string).GetMethod("IsNullOrEmpty"),null); 

事實上,雖然,我會尋找到Expression爲此 - 我相信有一個Compile for silverlight Expression,你不必學習IL!

請注意,如果有多個重載,您通常需要做更多的工作才能獲得MethodInfo(它恰巧string.IsNullOrEmpty易於使用)。另外請注意,「實例」方法應該使用OpCodes.Callvirt;靜態方法(如這個)應該使用OpCodes.Call

+1

+1 - 對我來說太快了。另外我想指出的是,你可能不想添加OpCodes.Nop語句,這可能是currSetIL.Emit(OpCodes.Call,typeof(string).GetMethod(「IsNullOrEmpty」)) - 更短,相同事情? – 2010-01-15 13:02:08

+0

@Benjamin:是的,絕對的「nop」是調試器的總開銷,可以丟棄。 – 2010-01-15 13:07:11

+0

好的,謝謝你的快速回答,(是的,nop是頭頂上的:-)但我把它,顯示1:1轉換形式MSIL到EMIT,命令) 因此總之有一個工具或者是讓我從MSIL到EMIT刺痛的東西。 MSIL代碼中還有很多其他行必須進行轉換嗎? 或者更好的是,我可以直接添加一個方法到生成的類型。 例如,像這樣的東西 property.SetSetMethod(MyMethod); //這不會工作,因爲SetMethod需要一個Methodbuilder而不是一個方法,所以我可以創建一個基於另一種方法?它會解決問題。 – ReLoad 2010-01-15 14:08:43

相關問題