リフレクション
最終更新:
atachi
型情報の取得
System::Typeクラス に型情報に関するアクセスができます。
Typeクラスの作成は次のように行います。
Type t = Type.GetType("MyClass"); // クラス名による取得
文字列で任意のクラスの型情報を取得
アプリケーションがアクセス可能な型情報の一覧を作成できるので、その中から取得したい型名を探し出す事で、 文字列から型情報を取得できる。
using System.Reflection;
class ObjectUtil{
public static System.Type GetTypeFromName(string name)
{
foreach(System.Type type in GetCurrendDomainAssemblyTypes())
{
if (String.Equals(type.FullName, name) || String.Equals(type.AssemblyQualifiedName, name))
return type;
}
}
public static IList<System.Type> GetCurrendDomainAssemblyTypes()
{
Assembly[] assemblies = System.AppDomain.CurrentDomain.GetAssemblies();
List<System.Type> types = new List<System.Type>();
foreach (System.Reflection.Assembly assembly in assemblies)
{
types.AddRange(assembly.GetTypes());
}
return types;
}
}
上記のようなクラスを用意しておけば、完全なクラス名を与えることでそのクラスの型情報を取得できる。
Type type = GetTypeFromName("System.String");
型情報の使い方
型情報を使ってインスタンスを作成
Activatorを使う方法が最も簡単。
ただし、対象のクラス宣言でデフォルトコンストラクタにアクセスできる場合に限られる。
引数を伴うコンストラクタを呼び出したりするには、コンストラクタ情報(ConstructorInfo)を取得して呼び出す必要がある。
System.Type type = typeof(String);
object instance = Activator.CreateInstance(type);
型情報からの配列型作成
System.Type type = typeof(String); object instance = Activator.CreateInstance(type);
このように作り出した場合のinstance変数はString型であることが型推論によりわかるため、問題はありません。
しかし、型情報から動的に配列型を作成するには、工夫が必要で必ず配列のサイズをコンストラクタを使って指定します。
System.Type type = typeof(String);
System.Type typeStrings = type.MakeArrayType(); // String[]のような型。
// 配列型をインスタンス化
// - コンストラクタを取得する
ConstructorInfo[] Constructors = t.GetConstructors();
// - コンストラクタをInvokeする。
// パラメータは1つで、作成したい配列のサイズが入る。
var instance = Constructors[0].Invoke(new object[]{1}); // "new String[1]" と同じ
配列を初期化
上記のように動的に作成した配列型に初期値を与えることはできません。
よって、作成したインスタンスにArray.Copyを使って要素をコピーします。
Array.Copy(new String[]{"埼玉"}, (System.Array)instance, 1);
foreach(object element in (System.Array)instance)
{
System.Console.WriteLine(element.ToString()); // echo "埼玉"
}
型情報による操作
Type t = Type.GetType("MyClass"); // クラス名による取得
// 型情報からインスタンスの生成
MyClass obj = Activator.CreateInstance(t);
t.GetField("width").SetValue(obj, 19); // objインスタンスのwidthフィールドへ値を設定
int width = (int)t.GetField("width").GetValue(obj); // objインスタンスのwidthフィールドの取得
ジェネリクスとリフレクション
ジェネリックの型情報をリフレクションで取得します。
class Program
{
static void Main(string[] args)
{
Collection<Student> students = new Collection<Student>();
Type clazz = students.GetType();
Console.WriteLine("ジェネリクスであるか : " + clazz.IsGenericType);
Type genClazz = clazz.GetGenericArguments()[0];
Console.WriteLine("ジェネリック型 : " + genClazz.Name);
}
}
class Student
{
public string name;
}