IL合集二

  • A+
所属分类:.NET技术
摘要

   在第一篇关于IL的文章中,我们写了一些IL的相加,创建对象,循环以及实现TryCatch的一些功能,接下来,为大家带上后续关于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 值类型转引用类型