【C#】System.Reflection.Emitで動的コード生成 初回

### 注意 ###
初めて書く記事ですのでお見苦しい点があると思います。
そのため温かい目でご覧ください。
## C#でメタプログラミングをする方法 ###
1. **Refrection.Emit(Emitter)** 
2. Expression.Tree(式木)
3. CodeDOM
4. T4(Text Template Transformation Toolkit)

自分が認識しているのは標準ライブラリはこんな感じです
今回は 1 のRefrection.Emitを使います
## Refrection.Emitについて ##
- メリット
    - .netの仕組みを知れ、理解が深まる
    - C#で使えない機能を扱える
    - 他の動的コード生成の方法に比べ高速
    - .NET Framework 2.0といった古いバージョンでも利用が可能
- デメリット
    - CIL(MSIL)の知識が必要(今後回解説する予定です)
    - 情報が少ない

このようにRefrection.Emitでは古いバージョンで動かしたい！.netの技術を深めたい！自作の言語を作りたい！コンパイラを作りたい！といった方にお勧めです。

しかしながら、簡単にコード生成をしたい！速度はどうでもいいからコードを生成を手っ取り早くやりたい！といった方にはCodeDOM、Expression.Treeをおすすめします。

##実際にコードを生成してみる##
今回は初回ですので、HelloWorldをしてみます
今回生成するファイルは以下の構文と同じ意味になります

```csharp:C#
class Program
{
    static void Main()
    {
        letter = "Hello World";
        System.Console.WriteLine(letter);
    }
}
```

### C#の構文 ###
環境はVS2019 .NET Freamwork4.7.2で、コンソールアプリケーション(.NET Freamwork)です
.net coreについては一部動かないため方法が見つかるか、機能が追加されるまでおまちください

```C#:C#
using System;
using System.Reflection;
using System.Reflection.Emit;

class Program
{
    static void Main()
    {
        //アセンブリの設定
        string projectName = "Hello World";
        AssemblyName assemblyName = new AssemblyName() { Name = projectName };//アセンブリの名前を設定する
        AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save);//アセンブリを生成する
        ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(projectName, projectName + ".exe", true);//アセンブリのモデルを生成する
        //クラスを宣言する
        TypeBuilder typeBuilder = moduleBuilder.DefineType("Program", TypeAttributes.Class);//クラスを設定
        MethodBuilder mainMethodBuilder = typeBuilder.DefineMethod("Main", MethodAttributes.Public | MethodAttributes.Static, typeof(void), Type.EmptyTypes);//メソッドの設定
        ILGenerator ilMain = mainMethodBuilder.GetILGenerator();//ILを指定する
        LocalBuilder msgLocal = ilMain.DeclareLocal(typeof(string));//stringの変数を宣言する
        msgLocal.SetLocalSymInfo("letter");//変数名を決める
        ilMain.Emit(OpCodes.Ldstr, "Hello World");//スタックにHello Worldをプッシュする(文字列の時)
        ilMain.Emit(OpCodes.Stloc, msgLocal);//スタックの一番上から現在の値をポップし変数に格納する
        ilMain.Emit(OpCodes.Ldloc, msgLocal);//スタックに変数からプッシュする
        ilMain.EmitCall(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }), null);//呼び出す
        ilMain.Emit(OpCodes.Ret);
        typeBuilder.CreateType();
        assemblyBuilder.SetEntryPoint(mainMethodBuilder);
        assemblyBuilder.Save(projectName+".exe");
    }
}
```

これでHello Worldを出力するexeファイルを出力します
出力先は実行ファイルを置いたパスに出力されます
8行目AssemblyBuilderを宣言するとき、引数にパスを追加することで出力先を指定できます。

```csharp
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save,任意のパス);
```
当たり前のようにプッシュとかポップとかって言ってますが、.netはレジスタではなくスタックで実装されています。またILはそのまま変数から呼び出すことができず、スタックに入れてから使う必要があります。
**pushではスタックに上から入れます**
**popではスタックの値を上から取り出します**
イメージでは本を積んで下から取り出せないようになっている感じです。
また、CILの命令はOpCodesというClassに含まれているフィールドで構成されています。それに、CILではスタックにポップ、プッシュするとき**型**によって変わります。

また、実行命令については以下のサイトをご参照ください
[OpCodes クラス](https://docs.microsoft.com/ja-jp/dotnet/api/system.reflection.emit.opcodes?view=netcore-3.1)

### IL Dasmでデコンパイルしたものを見てみましょう ###
Developer Command Promptで

```
ildasm
```
を実行することでIL Dasmが開かれます
そこに実行ファイルをドラッグアンドドロップで置くことでCILを見ることができます

CIL構文

```cil:cil
.method public static void  Main() cil managed
{
  .entrypoint
  // コード サイズ       13 (0xd)
  .maxstack  1
  .locals init ([0] string letter)
  IL_0000:  ldstr      "Hello"
  IL_0005:  stloc.0
  IL_0006:  ldloc.0
  IL_0007:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_000c:  ret
} // end of method Program::Main
```
こうなってたらちゃんとできてます。
### では出力ファイルを実行してみましょう ###
今回はConsole.ReadLine()を追加していないので、結果を見ることができないので
**コマンドプロンプト**で実行する必要があります。
実行したら以下のように表示されます。
これが表示されたら成功です。

```
Hello World
```

## 最後に ##
最後まで読んでいただきありがとうございます。
今回は初回ですが気が向いたら第二回以降も書こうと思います。
次回をするとしたら、staticメソッドの生成と、呼び出しについてやります。
また、番外として命令表をわかりやすくまとめたいと思います。