IL合集二


引言

   在第一篇關於IL的文章中,我們寫了一些IL的相加,創建對象,循環以及實現TryCatch的一些功能,接下來,為大家帶上后續關於IL的更新,其中包括,類型轉換,以及條件判斷,還有定義字段,定義屬性,定義事件,以及事件能夠實現多播委托的功能,最后還有定義枚舉。

類型轉換

   

var methodBydy = typeBulder.DefineMethod("Box", MethodAttributes.Public, CallingConventions.Standard, typeof(object), new Type[] { typeof(int) });
                var ilMethod = methodBydy.GetILGenerator();
                ilMethod.Emit(OpCodes.Nop);//不做任何操作
                ilMethod.Emit(OpCodes.Ldarg_1);//加載第一個參數到堆棧
                ilMethod.Emit(OpCodes.Box, typeof(int));//將int類型轉為引用類型並且推送到計算機堆棧
                ilMethod.Emit(OpCodes.Ret);//返回棧頂結果

上面的代碼是將值類型轉為引用類型,並且返回結果。

邏輯判斷

Brtrue

   

 var methods = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) });//輸出字符串
                    var method = typeBulder.DefineMethod("BrTrue", MethodAttributes.Public, CallingConventions.Standard, typeof(void), new Type[] { typeof(object) });
                    var il = method.GetILGenerator();
                    var trueLabel = il.DefineLabel();
                    il.Emit(OpCodes.Ldarg_1);
                    il.Emit(OpCodes.Brtrue, trueLabel);//第一個參數不是0或者不是null,或者不是false則跳轉到trueLabel標簽
                    il.Emit(OpCodes.Ret);
                    il.MarkLabel(trueLabel);
                    il.Emit(OpCodes.Ldstr, "參數是沒問題的");
                    il.Emit(OpCodes.Call, methods);//調用方法
                    il.Emit(OpCodes.Ret);

上面的代碼中定義了一個方法,入參為object類型,在下面IL代碼中是判斷這個參數是否為null或者是0,如果不是 就跳轉到truelabel標簽代碼,

Brfalse

    

 var methods = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) });//輸出字符串
                    var method = typeBulder.DefineMethod("Brfalse", MethodAttributes.Public, CallingConventions.Standard, typeof(void), new Type[] { typeof(object) });
                    var il = method.GetILGenerator();
                    var falseLabel = il.DefineLabel();
                    il.Emit(OpCodes.Ldarg_1);
                    il.Emit(OpCodes.Brfalse, falseLabel);//第一個參數是0或者是null,或者是false則跳轉到falseLabel標簽
                    il.Emit(OpCodes.Ret);
                    il.MarkLabel(falseLabel);
                    il.Emit(OpCodes.Ldstr, "參數是false,或者0,或者空引用");
                    il.Emit(OpCodes.Call, methods);//調用方法
                    il.Emit(OpCodes.Ret);

與上面的相反,Brfalse是判斷參數是否為空引用或者null或者是0;

定義字段,屬性,賦值

   

  var field = typeBulder.DefineField("customField", typeof(int), FieldAttributes.Private);//定義字段
                var proper = typeBulder.DefineProperty("CustomField", PropertyAttributes.None, typeof(int), null);//定義屬性
                var getMethod = typeBulder.DefineMethod("get_CustomField", MethodAttributes.Public, typeof(int), Type.EmptyTypes);//屬性的Get方法 就是Get關鍵字
                var setMethod = typeBulder.DefineMethod("set_CustomField", MethodAttributes.Public, null, new Type[] { typeof(int) });//屬性的Set方法 就是Set關鍵字
                var getIl = getMethod.GetILGenerator();//構造get方法體
                getIl.Emit(OpCodes.Ldarg_0);//加載自變量
                getIl.Emit(OpCodes.Ldfld, field);//看清楚是Ldfld,load field  不是 ldsfld load static  field  //將Field字段加載到堆棧
                getIl.Emit(OpCodes.Ret);//返回棧頂的field
                var setIl = setMethod.GetILGenerator();//構造set方法體
                setIl.Emit(OpCodes.Ldarg_0);//加載自變量
                setIl.Emit(OpCodes.Ldarg_1);//拿到第一個參數
                setIl.Emit(OpCodes.Stfld, field);//給field賦值
                setIl.Emit(OpCodes.Ret);//返回方法
                proper.SetGetMethod(getMethod);//設置屬性的get方法
                proper.SetSetMethod(setMethod);//設置屬性的set方法
                var getmh = typeBulder.DefineMethod("GetCustomField", MethodAttributes.Public, typeof(int), Type.EmptyTypes);//寫一個獲取屬性的方法
                var ilMh = getmh.GetILGenerator();
                ilMh.Emit(OpCodes.Nop);
                ilMh.Emit(OpCodes.Ldarg_0);//加載自變量
                ilMh.Emit(OpCodes.Call, proper.GetMethod);//調用屬性的get方法
                ilMh.Emit(OpCodes.Ret);//並且返回
                var setmh = typeBulder.DefineMethod("SetCustomField", MethodAttributes.Public, null, new Type[] { typeof(int) });//寫一個設置屬性的方法
                var setMhIl = setmh.GetILGenerator();
                setMhIl.Emit(OpCodes.Nop);//
                setMhIl.Emit(OpCodes.Ldarg_0);//加載自變量
                setMhIl.Emit(OpCodes.Ldarg_1);//獲取第一個參數
                setMhIl.Emit(OpCodes.Call, proper.SetMethod);//將第一個參數傳給set方法賦值
                setMhIl.Emit(OpCodes.Ret);//返回

   在C#中,由於編輯器對代碼進行了封裝所以,我們定義屬性的時候,是使用get set關鍵字去進行設置的,但是實際上get和set也是方法,在很久之前的版本記得是1.0的時候是沒有這兩個關鍵字的,當時定義屬性是和Java一樣需要定義get set方法,所以上面那段代碼,定義了一個屬性叫CustomField,那對應的屬性需要有get和set方法,那在get方法,只需要返回定義的字段信息,然后返回就可以了,在set方法中,只需要把參數賦值給定義的字段,就是先set方法。

定義事件以及實現多播

 var invokeMethod = typeof(Action<string>).GetMethod("Invoke");
                var eventField = typeBulder.DefineField("onChange", typeof(Action<string>), FieldAttributes.Private);//定義字段
                var eventProper = typeBulder.DefineEvent("OnChange", EventAttributes.None, typeof(Action<string>));//定義event
                var addMethod = typeBulder.DefineMethod("AddEvent", MethodAttributes.Public, null, new Type[] { typeof(Action<string>) });//定義event的add方法  關鍵字add
                var ilAdd = addMethod.GetILGenerator();
                ilAdd.Emit(OpCodes.Ldarg_0);//加載自變量
                ilAdd.Emit(OpCodes.Ldarg_1);//第一個參數加載到堆棧
                ilAdd.Emit(OpCodes.Stfld, eventField);//給字段賦值
                ilAdd.Emit(OpCodes.Ret);//返回
                eventProper.SetAddOnMethod(addMethod);//將set方法添加到屬性
                var removeMethod = typeBulder.DefineMethod("RemoveEvent", MethodAttributes.Public, null, new Type[] { typeof(Action<string>) });//定義event的remove方法,關鍵字remove
                var ilRemove = removeMethod.GetILGenerator();
                ilRemove.Emit(OpCodes.Ldarg_0);//加載自變量
                ilRemove.Emit(OpCodes.Ldarg_1);//第一個參數加載到堆棧
                ilRemove.Emit(OpCodes.Stfld, eventField);//給字段賦值
                ilRemove.Emit(OpCodes.Ret);
                eventProper.SetRemoveOnMethod(removeMethod);//將remove方法添加到屬性
                var raiseMh = typeBulder.DefineMethod("RaiseMethod", MethodAttributes.Public, null, Type.EmptyTypes);//定義觸發事件的方法
                var raiseIl = raiseMh.GetILGenerator();
                raiseIl.Emit(OpCodes.Ldarg_0);//加載自變量
                raiseIl.Emit(OpCodes.Ldfld, eventField);//加載字段到堆棧
                raiseIl.Emit(OpCodes.Ldstr, "Hello World!");//加載字符串參數到堆棧,
                raiseIl.Emit(OpCodes.Callvirt, invokeMethod);//將helloworld傳入方法
                raiseIl.Emit(OpCodes.Ret);//結束方法
                eventProper.SetRaiseMethod(raiseMh);
                var type = typeBulder.CreateType();
                var instance = Activator.CreateInstance(type);
                var events = type.GetEvent("OnChange");

                var action = new Action<string>(s =>
                {
                    Console.WriteLine(s);//輸出上方的helloworld
                });
                events.AddEventHandler(instance, action);
                events.RaiseMethod.Invoke(instance, new object[] { });
                events.RemoveEventHandler(instance, null); 

   眾所周知,事件是可以定義成委托類型,委托又涉及到了多播委托,這里不對反編譯后的委托進行過多的講解,只是通過Delegate的combine方法進行多個委托的連接從而實現一個多播委托,並且定義相關的add和remove的方法,以及觸發事件的方法

枚舉

   

 var em = moduleBulder.DefineEnum("LoginType", TypeAttributes.Public, typeof(int));
                em.DefineLiteral("UserPassWordType", 0);
                em.DefineLiteral("Other", 1);

   枚舉的定義其實很簡單,可以看一下上面的代碼。

結語

   今天的IL合集就到這里了,具體的項目中使用還是得結合具體的場景去實現。

 

Box 值類型轉引用類型


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM