Emit 辅助类
由于动态编译是基于 Emit
的,因此在定义构造函数、方法和属性时,都要使用到 IL(中间语言)
,在 DynamicMethod
实例或上下文 Context 中可以使用 EmitHelper
对象来编织 IL
代码。它是对 ILGenerator
类的全部操作的包装,以达到在使用 IL
指令时更加方便,具体的方法请参考 OpCodes
类的常量定义。为了保持与 IL
指令一致,EmitHelper
类的方法使用小写命名。
1、IL指令包装
与指令相关的方法或属性如下(举例):
add 属性:将两个值相加并将结果推送到计算堆栈上。
add_ovf 属性:将两个整数相加,执行溢出检查,并且将结果推送到计算堆栈上。
add_ovf_un 属性:将两个无符号整数值相加,执行溢出检查,并且将结果推送到计算堆栈上。
and 属性:计算两个值的按位“与”并将结果推送到计算堆栈上。
beq_s 方法:如果两个值相等,则将控制转移到目标指令(短格式)。
ldarg_0 属性:将索引为 0 的参数加载到计算堆栈上。
ldc_i4_ 方法:将指定的整数作为 int32 推送到计算堆栈上。
ldloc 方法:将指定索引处的局部变量加载到计算堆栈上。
callvirt 方法:对对象调用后期绑定方法,并且将返回值推送到计算堆栈上。
unbox 方法:将值类型的已装箱的表示形式转换为其未装箱的形式。
。。。。。。
最后表一列出了所有 IL
指令对应的方法或属性。
2、辅助方法
- ldarg 方法
将索引处的参数加载到堆栈上。IL
指令最多支持 ldarg_1、ldarg_2、ldarg_3,和 ldarg_s 方法,但使用起来不太简便,因此 ldarg(int index) 方法为他们提供了统一的调用。
- end 方法
方法本身没有具体的意义,仅在 EmitHelper
对象在使用了属性之后,再使用 end 方法以表结束。
3、其他方法
- Assert 方法
Assert 方法判断一个断言是否成立,如果成立则进行相应的链式编织。如下所示:
[TestMethod]
public void TestEmitAssert()
{
var callMethod = true; //用于模拟断言
var builder = new DynamicMethod("TestHello", typeof(bool), null);
var emiter = new EmitHelper(method.GetILGenerator())
.Assert(callMethod,
e => e.ldstr("fireasy")
.call(typeof(Helper).GetMethod("GetHello", new[] { typeof(string) })),
e => e.ldstr("hello fireasy"))
.call(typeof(Console).GetMethod("WriteLine", new[] { typeof(string) }))
.ldc_i4_1.ret();
var func = builder.CreateDelegate(typeof(Func<bool>));
Assert.IsTrue((bool)func.DynamicInvoke(null));
}
public class Helper
{
public static string GetHello(string name)
{
return "hello " + name;
}
}
//------方法原型--------
public static bool TestHello()
{
Console.WriteLine(Helper.GetHello("fireasy"));
return true;
}
//----------------------
- Each 方法
Each 方法用于遍列一个序列,将序列中的元素编辑到 EmitHelper
对象里。如下所示:
[TestMethod]
public void TestEmitEach()
{
var cities = new[] { "kunming", "chengdu", "guangzhou" };
var builder = new DynamicMethod("TestItems", typeof(int), new[] { typeof(List<string>) });
var emiter = new EmitHelper(method.GetILGenerator())
.Each(cities, (e, str, i) =>
{
e.ldarg_0.ldstr(str)
.callvirt(typeof(List<string>).GetMethod("Add"));
})
.ldarg_0.callvirt(typeof(List<string>).GetMethod("get_Count")).ret();
var items = new List<string>();
var func = builder.CreateDelegate(typeof(Func<List<string>, int>));
Assert.AreEqual(3, (int)func.DynamicInvoke(items));
}
//------方法原型--------
public static int TestItems(List<string> items)
{
items.Add("kunming");
items.Add("chengdu");
items.Add("guangzhou");
return items.Count;
}
//----------------------
- For 方法
For 方法用于循环一组数字,一般用在循环体内有共性的指令之时,如下所示:
[TestMethod]
public void TestEmitFor()
{
var method = new DynamicMethod("TestWrite", typeof(void),
new[] { typeof(string), typeof(string), typeof(int) });
var parameters = method.GetParameters();
var emiter = new EmitHelper(method.GetILGenerator())
.ldc_i4(parameters.Length)
.newarr(typeof(object))
.For(0, parameters.Length, (e, i) =>
{
e.dup.ldc_i4(i).ldarg(i)
.Assert(parameters[i].ParameterType.IsValueType,
e1 => e1.box(parameters[i].ParameterType))
.stelem_ref.end();
})
.call(typeof(string).GetMethod("Concat", new[] { typeof(object[]) }))
.call(typeof(Console).GetMethod("WriteLine", new[] { typeof(string) }))
.ret();
var action = method.CreateDelegate(typeof(Action<string, string, int>));
action.DynamicInvoke("fireasy", "kunming", 33);
}
//------方法原型--------
public static void TestWrite(string name, string city, int age)
{
Console.WriteLine(string.Concat(new object[] { name, city, age }));
}
//----------------------
4、表一:IL指令与方法/属性对应表
指令 | 方法 / 属性 |
---|---|
Add | P add |
Add.Ovf | P add_ovf |
Add.Ovf.Un | P add_ovf_un |
And | P and |
Arglist | P arglist |
Beq | M beq |
Beq.S | M beq_s |
Bge | M bge |
Bge.S | M bge_s |
Bge.Un | M bge_un |
Bge.Un.S | M bge_un_s |
Bgt | M bgt |
Bgt.S | M bgt_s |
Bgt.Un | M bgt_un |
Bgt.Un.S | M bgt_un_s |
Ble | M ble |
Ble.S | M ble_s |
Ble.Un | M ble_un |
Ble.Un.S | M ble_un_s |
Blt | M blt |
Blt.S | M blt_s |
Blt.Un | M blt_un |
Blt.Un.S | M blt_un_s |
Bne.Un | M bne_un |
Bne.Un.S | M bne_un_s |
Box | M box |
Br | M br |
Br.S | M br_s |
Break | P break |
Brfalse | M brfalse |
Brfalse.S | M brfalse_s |
Brtrue | M brtrue |
Brtrue.S | M brtrue_s |
Call | M call |
Calli | M calli |
Callvirt | M callvirt |
Castclass | M castclass |
Ceq | P ceq |
Cgt | P cgt |
Cgt.Un | P cgt_un |
Ckfinite | P ckfinite |
Clt | P clt |
Clt.Un | P clt_un |
Constrained | M constrained |
Conv.I | P conv_i |
Conv.I1 | P conv_i1 |
Conv.I2 | P conv_i2 |
Conv.I4 | P conv_i4 |
Conv.I8 | P conv_i8 |
Conv.Ovf.I | P conv_ovf_i |
Conv.Ovf.I.Un | P conv_ovf_i_un |
Conv.Ovf.I1 | P conv_ovf_i1 |
Conv.Ovf.I1.Un | P conv_ovf_i1_un |
Conv.Ovf.I2 | P conv_ovf_i2 |
Conv.Ovf.I2.Un | P conv_ovf_i2_un |
Conv.Ovf.I4 | P conv_ovf_i4 |
Conv.Ovf.I4.Un | P conv_ovf_i4_un |
Conv.Ovf.I8 | P conv_ovf_i8 |
Conv.Ovf.I8.Un | P conv_ovf_i9_un |
Conv.Ovf.U | P conv_ovf_u |
Conv.Ovf.U.Un | P conv_ovf_u_un |
Conv.Ovf.U1 | P conv_ovf_u1 |
Conv.Ovf.U1.Un | P conv_ovf_u1_un |
Conv.Ovf.U2 | P conv_ovf_u2 |
Conv.Ovf.U2.Un | P conv_ovf_u2_un |
Conv.Ovf.U4 | P conv_ovf_u4 |
Conv.Ovf.U4.Un | P conv_ovf_u4_un |
Conv.Ovf.U8 | P conv_ovf_u8 |
Conv.Ovf.U8.Un | P conv_ovf_u8_un |
Conv.R.Un | P conv_r_un |
Conv.R4 | P conv_r4 |
Conv.R8 | P conv_r8 |
Conv.U | P conv_u |
Conv.U1 | P conv_u1 |
Conv.U2 | P conv_u2 |
Conv.U4 | P conv_u4 |
Conv.U8 | P conv_u8 |
Cpblk | P cpblk |
Cpobj | M cpobj |
Div | P div |
Div.Un | P div_un |
Dup | P dup |
Endfilter | P endfilter |
Endfinally | P endfinally |
Initblk | P initblk |
Initobj | M initobj |
Isinst | M isinst |
Jmp | M jmp |
Ldarg | M ldarg |
Ldarg.0 | P ldarg_0 |
Ldarg.1 | P ldarg_1 |
Ldarg.2 | P ldarg_2 |
Ldarg.3 | P ldarg_3 |
Ldarg.S | M ldarg_s |
Ldarga | P ldarga |
Ldarga.S | P ldarga_s |
Ldc.I4 | M ldc_i4 |
Ldc.I4.0 | P ldc_i4_0 |
Ldc.I4.1 | P ldc_i4_1 |
Ldc.I4.2 | P ldc_i4_2 |
Ldc.I4.3 | P ldc_i4_3 |
Ldc.I4.4 | P ldc_i4_4 |
Ldc.I4.5 | P ldc_i4_5 |
Ldc.I4.6 | P ldc_i4_6 |
Ldc.I4.7 | P ldc_i4_7 |
Ldc.I4.8 | P ldc_i4_8 |
Ldc.I4.M1 | P ldc_i4_m1 |
Ldc.I4.S | M ldc_i4_s |
Ldc.I8 | M ldc_i8 |
Ldc.R4 | M ldc_r4 |
Ldc.R8 | M ldc_r8 |
Ldelem | M ldelem |
Ldelem.I | P ldelem_i |
Ldelem.I1 | P ldelem_i1 |
Ldelem.I2 | P ldelem_i2 |
Ldelem.I4 | P ldelem_i4 |
Ldelem.I8 | P ldelem_i8 |
Ldelem.R4 | P ldelem_r4 |
Ldelem.R8 | P ldelem_r8 |
Ldelem.Ref | P ldelem_ref |
Ldelem.U1 | P ldelem_u1 |
Ldelem.U2 | P ldelem_u2 |
Ldelem.U4 | P ldelem_u4 |
Ldelema | M ldelema |
Ldfld | M ldfld |
Ldflda | M ldflda |
Ldftn | M ldftn |
Ldind.I | P ldind_i |
Ldind.I1 | P ldind_ii |
Ldind.I2 | P ldind_i2 |
Ldind.I4 | P ldind_i4 |
Ldind.I8 | P ldind_i8 |
Ldind.R4 | P ldind_r4 |
Ldind.R8 | P ldind_r8 |
Ldind.Ref | P ldind_ref |
Ldind.U1 | P ldind_u1 |
Ldind.U2 | P ldind_u2 |
Ldind.U4 | P ldind_u4 |
Ldlen | P ldlen |
Ldloc | M ldloc |
Ldloc.0 | P ldloc_0 |
Ldloc.1 | P ldloc_1 |
Ldloc.2 | P ldloc_2 |
Ldloc.3 | P ldloc_3 |
Ldloc.S | P ldloc_s |
Ldloca | M ldloca |
Ldloca.S | M ldloc_s |
Ldnull | P ldnull |
Ldobj | M ldobj |
Ldsfld | M ldsfld |
Ldsflda | M ldsflda |
Ldstr | M ldstr |
Ldtoken | M ldtoken |
Ldvirtftn | M ldvirtftn |
Leave | M leave |
Leave.S | M leave_s |
Localloc | P localloc |
Mkrefany | M mkrefany |
Mul | P mul |
Mul.Ovf | P mul_ovf |
Mul.Ovf.Un | P mul_ovf_un |
Neg | P neg |
Newarr | M newarr |
Newobj | M newobj |
Nop | P nop |
Not | P not |
Or | P or |
Pop | P pop |
Prefix1 | - |
Prefix2 | - |
Prefix3 | - |
Prefix4 | - |
Prefix5 | - |
Prefix6 | - |
Prefix7 | - |
Prefixref | - |
Readonly | P readonly |
Refanytype | P refanytype |
Refanyval | M refanyval |
Rem | P rem |
Rem.Un | P rem_un |
Ret | M ret |
Rethrow | P rethrow |
Shl | P shl |
Shr | P shr |
Shr.Un | P shr_un |
Sizeof | M sizeof |
Starg | M starg |
Starg.S | M starg_s |
Stelem | M stelem |
Stelem.I | P stelem_i |
Stelem.I1 | P stelem_i1 |
Stelem.I2 | P stelem_i2 |
Stelem.I4 | P stelem_i4 |
Stelem.I8 | P stelem_i8 |
Stelem.R4 | P stelem_r4 |
Stelem.R8 | P stelem_r8 |
Stelem.Ref | P stelem_ref |
Stfld | M stfld |
Stind.I | P stind_i |
Stind.I1 | P stind_i1 |
Stind.I2 | P stind_i2 |
Stind.I4 | P stind_i4 |
Stind.I8 | P stind_i8 |
Stind.R4 | P stind_r4 |
Stind.R8 | P stind_r8 |
Stind.Ref | P stind_ref |
Stloc | M stloc |
Stloc.0 | P stloc_0 |
Stloc.1 | P stloc_1 |
Stloc.2 | P stloc_2 |
Stloc.3 | P stloc_3 |
Stloc.S | P stloc_s |
Stobj | M stobj |
Stsfld | M stsfld |
Sub | P sub |
Sub.Ovf | P sub_ovf |
Sub.Ovf.Un | P sub_ovf_un |
Switch | M switch |
Tailcall | P tailcall |
Throw | P throw |
Unaligned | M unaligned |
Unbox | M unbox |
Unbox.Any | M unbox_any |
Volatile | P volatile |
Xor | P xor |