这是一篇关于IL和反射Emit的文章(所以不喜欢IL或者Emit的就没必要往下看了),要求读者对IL和Emit工作原理较了解。所有分析IL均在Visual Studio 2010 SP1下编译生成。(其他编译器不一定100%结果一样但逻辑上肯定是等价的,希望读者学到“为什么”,而不是“是什么”)。

 

 

 

 

返回目录

分析if-else

C#中的if-else:

    if (条件)

        //为true代码

    else

        //为false代码

 

if-else的IL执行逻辑:

条件为真:goto

//false代码

goto 退出

//true代码

退出

 

 

来分析一个示例程序:

C#:

        static void doo(bool b)

        {

            if(b)

                Console.WriteLine(1);

            else

                Console.WriteLine(2);

        }

 

IL:

    .maxstack 2

    .locals init (

        [0] bool CS$4$0000)

    L_0000: nop

    L_0001: ldarg.0   //b进栈

    L_0002: ldc.i4.0  //0(false)进栈

    L_0003: ceq       //比较b和false

    L_0005: stloc.0   //将结果赋值给临时bool

    L_0006: ldloc.0   //加载bool

    L_0007: brtrue.s L_0012  //如果false,跳至L_0012

    L_0009: ldc.i4.1  //true代码

    L_000a: call void [mscorlib]System.Console::WriteLine(int32)

    L_000f: nop 

    L_0010: br.s L_0019 //跳至返回

    L_0012: ldc.i4.2  //false代码

    L_0013: call void [mscorlib]System.Console::WriteLine(int32)

    L_0018: nop

    L_0019: ret //返回

 

 

 

返回目录

Emit创建if-else动态方法

有了上面的知识,就可以自己创建一个有if-else语句的动态方法,比如这样一个方法:

        static void test(bool b)

        {

            if(b)

                Console.WriteLine("真");

            else

                Console.WriteLine("假");

        }

 

使用反射Emit创建并运行,代码:

        //+ using System.Reflection;

        //+ using System.Reflection.Emit;

        static void Main(string[] args)

        {

            //创建DynamicMethod对象

            var dm = GetIfElse();

 

            //测试

            dm.Invoke(null, new object[] { true });

            dm.Invoke(null, new object[] { false });

        }

 

        static DynamicMethod GetIfElse()

        {

            var dm = new DynamicMethod("", null, new Type[] { typeof(bool) });

            var gen = dm.GetILGenerator();

 

            Label lbFalse = gen.DefineLabel();

            Label lbRet = gen.DefineLabel();

 

            //判断

            gen.Emit(OpCodes.Ldarg_0);

            gen.Emit(OpCodes.Ldc_I4, 1);

            gen.Emit(OpCodes.Ceq);

            //如果false: 跳至false代码

            gen.Emit(OpCodes.Brfalse, lbFalse);

            //true代码

            gen.EmitWriteLine("真");

            //跳至退出

            gen.Emit(OpCodes.Br, lbRet);

            //false代码

            gen.MarkLabel(lbFalse);

            gen.EmitWriteLine("假");

            //退出代码

            gen.MarkLabel(lbRet);

            gen.Emit(OpCodes.Ret);

 

            return dm;

        }

 

输出:

 

OK!

 

 

 

 

返回目录

分析while

C#中的while:

            while (条件)

            {

                //true代码

            }

 

 

IL中while执行逻辑:

goto 判断

//true代码

判断

条件为真:goto

 

分析代码,C#:

        static void doo(bool b)

        {

            while (b)

            {

                Console.WriteLine("TRUE");

            }

        }

 

IL:

    .maxstack 1

    .locals init (

        [0] bool CS$4$0000)

    L_0000: nop

    L_0001: br.s L_0010  //跳至判断

    L_0003: nop          //true代码

    L_0004: ldstr "TRUE"

    L_0009: call void [mscorlib]System.Console::WriteLine(string)

    L_000e: nop

    L_000f: nop

    L_0010: ldarg.0     //开始判断,载入b

    L_0011: stloc.0

    L_0012: ldloc.0     //将b的值赋予临时变量

    L_0013: brtrue.s L_0003 //如果为true,跳至true代码

    L_0015: ret

 

 

 

 

返回目录

Emit创建while动态方法

上面懂了的话,创建一个while循环就非常简单了,我们将动态创建这样一个方法:

        static void test(bool b)

        {

            if(b)

                Console.WriteLine("TRUE");

        }

 

代码:

        //+ using System.Reflection;

        //+ using System.Reflection.Emit;

        static void Main(string[] args)

        {

            //创建DynamicMethod对象

            var dm = GetWhile();

 

            //测试

            dm.Invoke(null, new object[] { false });

            Console.WriteLine("参数false,结束,等待3秒后运行参数true");

            System.Threading.Thread.Sleep(3000);

            dm.Invoke(null, new object[] { true });

        }

 

        static DynamicMethod GetWhile()

        {

            var dm = new DynamicMethod("", null, new Type[] { typeof(bool) });

            var gen = dm.GetILGenerator();

 

            Label lbCondition = gen.DefineLabel();

            Label lbTrue = gen.DefineLabel();

 

            //跳至判断

            gen.Emit(OpCodes.Br, lbCondition);

 

            //标记True代码

            gen.MarkLabel(lbTrue);

 

            gen.EmitWriteLine("TRUE");

 

            //标记判断代码

            gen.MarkLabel(lbCondition);

            //判断

            gen.Emit(OpCodes.Ldarg_0);

            gen.Emit(OpCodes.Ldc_I4, 1);

            gen.Emit(OpCodes.Ceq);

            //如果True,跳至true代码

            gen.Emit(OpCodes.Brtrue, lbTrue);

 

            gen.Emit(OpCodes.Ret);

            return dm;

        }

 

程序输出,当然false参数没有任何输出,然后等3秒后,无限输出TRUE

参数false,结束,等待3秒后运行参数true

TRUE

TRUE

TRUE

TRUE

...

 

 

 

 

返回目录

分析for

C#中的for

            for (定义; 判断; 追加动作)

            {

                //动作

            }

 

IL中for执行逻辑:

goto 判断

动作

追加动作

 

判断

条件为真:goto 动作

呵呵,看似略复杂的for循环其实也是很简单的。

 

分析代码:

            for (int i = 0; i < 10; i++)

            {

                Console.WriteLine(i);

            }

 

IL:

    .maxstack 2

    .locals init (

        [0] int32 i,

        [1] bool CS$4$0000)

    L_0000: nop

    L_0001: ldc.i4.0    

    L_0002: stloc.0      //i=0

    L_0003: br.s L_0012  //跳至判断

    L_0005: nop          //true代码

    L_0006: ldloc.0      //动作代码

    L_0007: call void [mscorlib]System.Console::WriteLine(int32)

    L_000c: nop          //动作代码结束

    L_000d: nop          //追加动作代码

    L_000e: ldloc.0      //i++

    L_000f: ldc.i4.1

    L_0010: add

    L_0011: stloc.0      //更新i,追加动作代码结束

    L_0012: ldloc.0     //判断代码

    L_0013: ldc.i4.s 10 //10进栈

    L_0015: clt         //<=判断指令,判断i是否小于10

    L_0017: stloc.1

    L_0018: ldloc.1     //将结果存入临时本地bool变量

    L_0019: brtrue.s L_0005  //如果为true,跳至true代码

    L_001b: ret

 

 

 

 

返回目录

Emit创建for动态方法

我们将动态创建这样一个方法:

        static void test(int c)

        {

            for (int i = 0; i < c; i++)

            {

                Console.WriteLine(i);

            }

        }

 

代码:

        //+ using System.Reflection;

        //+ using System.Reflection.Emit;

        static void Main(string[] args)

        {

            //创建DynamicMethod对象

            var dm = GetFor();

 

            //测试

            dm.Invoke(null, new object[] { 3 });

        }

 

        static DynamicMethod GetFor()

        {

            var dm = new DynamicMethod("", null, new Type[] { typeof(int) });

            var gen = dm.GetILGenerator();

 

            //临时变量i

            LocalBuilder locI = gen.DeclareLocal(typeof(int));

            Label lbCondition = gen.DefineLabel();

            Label lbTrue = gen.DefineLabel();

 

            //i=0

            gen.Emit(OpCodes.Ldc_I4_0);

            gen.Emit(OpCodes.Stloc, locI);

 

            //跳至判断

            gen.Emit(OpCodes.Br, lbCondition);

 

            //标记True代码

            gen.MarkLabel(lbTrue);

 

            //Console.WriteLine(i)

            gen.Emit(OpCodes.Ldloc, locI);

            gen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }));

 

            //追加代码

            //i++

            gen.Emit(OpCodes.Ldloc, locI);

            gen.Emit(OpCodes.Ldc_I4_1);

            gen.Emit(OpCodes.Add);

            gen.Emit(OpCodes.Stloc, locI);

 

            //判断代码

            gen.MarkLabel(lbCondition);

            gen.Emit(OpCodes.Ldloc, locI);

            gen.Emit(OpCodes.Ldarg_0);

            gen.Emit(OpCodes.Clt);

            //如果True,跳至true代码

            gen.Emit(OpCodes.Brtrue, lbTrue);

 

            gen.Emit(OpCodes.Ret);

            return dm;

        }

 

 

输出:

0

1

2