リフレクションを利用して文字列からクラス操作

実行時型情報 - C# によるプログラミング入門 | ++C++; // 未確認飛行 C


リフレクションとはプログラム実行時にクラス等のメタデータを取り出したりなんかしたりできる機能みたいです。

これだけだとなんのこっちゃわからないのですが、要するに文字列からインスタンスを生成したりとか色々できる機能って感じですかね。

using System;

class Class {
    public int i;
    
    public void output (int j) {
        Console.WriteLine(i+j);
    }
}

class Program {
    static void Main() {
        var cobj = new Class();
        cobj.i = 100;
        cobj.output(50);
    }
}
$ main
150

さて上記のような単にクラスをnewして値を設定してメソッドを呼ぶだけの単純な処理を、リフレクションを使って書き直してみます。

using System;
using System.Reflection;

class Class {
    public int i;
    
    public void output (int j) {
        Console.WriteLine(i+j);
    }
}

class Program {
    static void Main() {
        // Class型の情報
        Type t = Type.GetType("Class");
        
        // var cobj = new Class();の部分
        object o = Activator.CreateInstance(t);
        
        // cobj.i = 100;の部分
        t.GetField("i").SetValue(o,100);
        
        // Class.outputメソッド情報
        MethodInfo m = t.GetMethod("output");
        
        // cobj.output(50);の部分
        m.Invoke(o,new object[]{ 50 });
    }
}

このようになります。クラス名やフィールド名等、全て文字列で指定することが可能となってます。面白い機能ですね。

ちなみに上記処理をコンパイルすると以下のような警告がでます。

$ csc main.cs
Microsoft (R) Visual C# 2010 Compiler version 4.0.30319.1
Copyright (C) Microsoft Corporation. All rights reserved.

main.cs(5,13): warning CS0649: フィールド 'Class.i' は割り当てられません。常に既定値 0 を使用します。

恐らくこれは、、リフレクションを利用してiに値を設定しているのでコンパイルではiに値が設定されてるかどうかが検出できないために出る警告のようですね。

またメソッド呼び出しの引数の型がobjectになったりと、コンパイル時チェックが働かないのでリフレクションの機能を使う場合は注意が必要ですね。

あと速度的にもかなり遅いらしく、一度だけ通る処理等であれば体感出来る程ではないものの、ループ等で繰り返し処理するようなケースではあまり使わない方が良いみたいです。

使いどころが難しいですね。

ちなみに

    // Class型の情報
    Type t = Type.GetType("Class");

の部分ですが、typeofを使って以下のようにも書けます。

    // Class型の情報
    Type t = typeof(Class);

ただし、typeofは型名を指定しないといけないので文字列から型情報を取るGetTypeの方と使い分けが必要ですね。