ILバイトコードを取得

ちょっと前にWindows.Formsを見ていくようなことを言っていましたが、GUI関連は画像がない分かり難く日記向けなネタじゃないのであっさり止めて、クラスライブラリ探索にしました。(^^;
今回はリフレクション関連で追加されたMethodBodyを弄ってみました。

#region Using directives

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;

#endregion

namespace ConsoleApplication1
{
    class Program
    {
        static void SayHello(string name)
        {
            int a = 10;
            int b = 20;
            int c = a + b;
            Console.WriteLine(c);
            Console.WriteLine("Hello " + name);
        }

        static int GetInt32(byte code, int index)
        {
            byte b = new byte[4];
            Array.Copy(code, index, b, 0, b.Length);
            return BitConverter.ToInt32(b, 0);
        }

        static void Main(string args)
        {
            Type t = typeof(Program);
            // SayHelloを取得
            MethodInfo mi = t.GetMethod("SayHello", 
                BindingFlags.Static | BindingFlags.NonPublic);
            // MethodyBodyを取得
            MethodBody mb = mi.GetMethodBody();

            int i = 0;
            // SayHelloのILバイトコードを取得
            byte code = mb.GetILAsByteArray();
            // 力業でバイトコードを文字変換(^^;
            while (i < code.Length)
            {
                int op = code[i++];
                if (OpCodes.Ldstr.Value == op)
                {
                    Console.WriteLine("{0}{1:X}", 
                        OpCodes.Ldstr.ToString().PadRight(10), GetInt32(code, i));
                    i += 4;
                }
                else if (OpCodes.Call.Value == op)
                {
                    Console.WriteLine("{0}{1:X}", 
                        OpCodes.Call.ToString().PadRight(10), GetInt32(code, i));
                    i += 4;
                }
                else if (OpCodes.Ret.Value == op)
                    Console.WriteLine(OpCodes.Ret);
                else if (OpCodes.Ldarg_0.Value == op)
                    Console.WriteLine(OpCodes.Ldarg_0);
                else if (OpCodes.Stloc_0.Value == op)
                    Console.WriteLine(OpCodes.Stloc_0);
                else if (OpCodes.Stloc_1.Value == op)
                    Console.WriteLine(OpCodes.Stloc_1);
                else if (OpCodes.Stloc_2.Value == op)
                    Console.WriteLine(OpCodes.Stloc_2);
                else if (OpCodes.Stloc_1.Value == op)
                    Console.WriteLine(OpCodes.Stloc_1);
                else if (OpCodes.Ldloc_0.Value == op)
                    Console.WriteLine(OpCodes.Ldloc_0);
                else if (OpCodes.Ldloc_1.Value == op)
                    Console.WriteLine(OpCodes.Ldloc_1);
                else if (OpCodes.Ldloc_2.Value == op)
                    Console.WriteLine(OpCodes.Ldloc_2);
                else if (OpCodes.Add.Value == op)
                    Console.WriteLine(OpCodes.Add);
                else if (OpCodes.Ldc_I4_S.Value == op)
                    Console.WriteLine("{0}{1}", 
                        OpCodes.Ldc_I4_S.ToString().PadRight(10), code[i++]);
                else
                    Console.WriteLine(op.ToString("X2"));
            }
            Console.ReadLine();
        }
    }
}
/* 結果
ldc.i4.s  10
stloc.0
ldc.i4.s  20
stloc.1
ldloc.0
ldloc.1
add
stloc.2
ldloc.2
call      A00000F
ldstr     70000001
ldarg.0
call      A000010
call      A000011
ret */

実行時にILコードを持ってこれるのは良いのですが、それを扱うクラスが用意されていないのは辛いですね。自力でちまちまはやりたくない。C#のパーサが相変わらず実装されていないのも合わせて何とかして貰いたいです。(^^;

うーん、bit和演算子の前後にスペース入れないとソースが崩れる・・・