Typeオブジェクトで表された型のインスタンスの作成、メソッドの呼び出し、プロパティ、フィールドの設定と取得の方法について説明します。
ここでは、次のようなクラスが宣言されているものとします。
Namespace MyNamespace Public Class TestClass 'フィールド Private PrivateField As Integer Public StringArray() As String 'プロパティ Public Property PublicProperty() As Integer Get Return PrivateField End Get Set(ByVal Value As Integer) PrivateField = Value End Set End Property 'インデクサ Default Public Property Item(ByVal index As Integer) As String Get Return index.ToString() End Get Set(ByVal Value As String) End Set End Property 'コンストラクタ Public Sub New(ByVal val As Integer) PrivateField = val StringArray = New String() {"1", "2", "3"} End Sub Public Sub New() PrivateField = 0 StringArray = New String() {"1", "2", "3"} End Sub 'メソッド Public Overloads Function PublicMethod( _ ByVal num1 As Integer, ByVal num2 As Integer) As String Return (num1 - num2).ToString() End Function Public Overloads Function PublicMethod( _ ByVal num1 As Integer) As String Return num1.ToString() End Function Public Overloads Function PublicMethod() As String Return PublicMethod(0) End Function '静的メソッド Public Overloads Shared Function StaticMethod( _ ByVal num1 As Integer, ByVal num2 As Integer) As Integer Return num1 + num2 End Function Public Overloads Shared Function StaticMethod( _ ByVal num1 As Integer, ByVal num2 As Integer, _ ByRef num3 As Integer) As Integer Dim sum As Integer = num1 + num2 + num3 num3 = num1 - num2 - num3 Return sum End Function End Class End Namespace
namespace MyNamespace { public class TestClass { //フィールド private int PrivateField; public string[] StringArray; //プロパティ public int PublicProperty { get { return PrivateField; } set { PrivateField = value; } } //インデクサ public string this[int index] { get { return index.ToString(); } set { } } //コンストラクタ public TestClass(int val) { PrivateField = val; StringArray = new string[] {"1", "2", "3"}; } public TestClass() { PrivateField = 0; StringArray = new string[] {"1", "2", "3"}; } //メソッド public string PublicMethod(int num1, int num2) { return (num1 - num2).ToString(); } public string PublicMethod(int num1) { return num1.ToString(); } public string PublicMethod() { return PublicMethod(0); } //静的メソッド public static int StaticMethod(int num1, int num2) { return num1 + num2; } public static int StaticMethod( int num1, int num2, ref int num3) { int sum = num1 + num2 + num3; num3 = num1 - num2 - num3; return sum; } } }
Typeオブジェクトのメンバを呼び出すには、InvokeMemberメソッドを使用します。InvokeMemberメソッドにより、インスタンスの作成、メソッドの呼び出し、プロパティ、フィールドの設定と取得がすべてできます。
次にInvokeMemberメソッドを用いて、TestClassクラスのメンバを呼び出す例を示します。
'Imports System.Reflection 'がソースファイルの一番上に書かれているものとする Dim num As Integer Dim str As String 'TestClassクラスのTypeオブジェクトを取得する Dim t As Type = GetType(MyNamespace.TestClass) '***** インスタンスの作成 ***** 'TestClassのインスタンスを作成 'target = New MyNamespace.TestClass(100) 'と同等 Dim target As Object = t.InvokeMember(Nothing, _ BindingFlags.CreateInstance, _ Nothing, _ Nothing, _ New Object() {100}) '***** メソッドの実行 ***** 'PublicMethodメソッドを実行 'str = target.PublicMethod(12) 'と同等 str = CStr(t.InvokeMember("PublicMethod", _ BindingFlags.InvokeMethod, _ Nothing, _ target, _ New Object() {12})) '静的メソッドStaticMethodを実行 'num = MyNamespace.TestClass.StaticMethod(1, 2) 'と同等 num = CInt(t.InvokeMember("StaticMethod", _ BindingFlags.InvokeMethod, _ Nothing, _ Nothing, _ New Object() {1, 2})) 'refパラメータで返される値を取得 'num = MyNamespace.TestClass.StaticMethod(1, 2, 0) 'と同等 Dim objs() As Object = {1, 2, 0} num = CInt(t.InvokeMember("StaticMethod", _ BindingFlags.InvokeMethod, _ Nothing, _ Nothing, _ objs)) 'refパラメータで受け取った値を表示 Console.WriteLine(objs(2)) 'パラメータの名前でパラメータを指定する 'str = target.PublicMethod(num2:=5, num1:=7) 'と同等 str = CStr(t.InvokeMember("PublicMethod", _ BindingFlags.InvokeMethod, _ Nothing, target, _ New Object() {5, 7}, _ Nothing, _ Nothing, _ New String() {"num2", "num1"})) '***** プロパティの設定と取得 **** 'PublicPropertyプロパティを設定 'target.PublicProperty = 100 'と同等 t.InvokeMember("PublicProperty", _ BindingFlags.SetProperty, _ Nothing, _ target, _ New Object() {100}) 'PublicPropertyプロパティを取得 'num = target.PublicProperty 'と同等 num = CInt(t.InvokeMember("PublicProperty", _ BindingFlags.GetProperty, _ Nothing, _ target, _ Nothing)) 'インデクサの指定したインデックスの要素を設定 'target(1) = "two" 'と同等 t.InvokeMember("Item", _ BindingFlags.SetProperty, _ Nothing, _ target, _ New Object() {1, "two"}) 'インデクサの指定したインデックスの要素を取得 'str = target(1) 'と同等 str = CStr(t.InvokeMember("Item", _ BindingFlags.GetProperty, _ Nothing, _ target, _ New Object() {1})) '***** フィールドの設定と取得 ***** 'PrivateFieldフィールドを設定 'target.PrivateField = 0 'と同等(ただし、通常プライベートフィールドにはアクセス不可) t.InvokeMember("PrivateField", _ BindingFlags.Public Or BindingFlags.NonPublic Or _ BindingFlags.Instance Or BindingFlags.SetField, _ Nothing, _ target, _ New Object() {0}) 'PrivateFieldフィールドを取得 'num = target.PrivateField 'と同等(ただし、通常プライベートフィールドにはアクセス不可) num = CInt(t.InvokeMember("PrivateField", _ BindingFlags.Public Or BindingFlags.NonPublic Or _ BindingFlags.Instance Or BindingFlags.GetField, _ Nothing, _ target, _ Nothing)) '配列StringArrayフィールドの0番目の値を設定 'target.StringArray(0) = "ゼロ" 'と同等 t.InvokeMember("StringArray", _ BindingFlags.SetField, _ Nothing, _ target, _ New Object() {0, "ゼロ"}) '配列StringArrayフィールドの0番目の値を取得 'str = target.StringArray(0) 'と同等 str = CStr(t.InvokeMember("StringArray", _ BindingFlags.GetField, _ Nothing, _ target, _ New Object() {0}))
//using System.Reflection; //がソースファイルの一番上に書かれているものとする int num; string str; //TestClassクラスのTypeオブジェクトを取得する Type t = typeof(MyNamespace.TestClass); //***** インスタンスの作成 ***** //TestClassのインスタンスを作成 //target = new MyNamespace.TestClass(100) //と同等 object target = t.InvokeMember(null, BindingFlags.CreateInstance, null, null, new object[] {100}); //***** メソッドの実行 ***** //PublicMethodメソッドを実行 //str = target.PublicMethod(12) //と同等 str = (string) t.InvokeMember("PublicMethod", BindingFlags.InvokeMethod, null, target, new object[] {12}); //静的メソッドStaticMethodを実行 //num = MyNamespace.TestClass.StaticMethod(1, 2) //と同等 num = (int) t.InvokeMember("StaticMethod", BindingFlags.InvokeMethod, null, null, new object[] {1, 2}); //refパラメータで返される値を取得 //num = MyNamespace.TestClass.StaticMethod(1, 2, ref 0) //と同等 object[] objs = new object[] {1, 2, 0}; num = (int) t.InvokeMember("StaticMethod", BindingFlags.InvokeMethod, null, null, objs); //refパラメータで受け取った値を表示 Console.WriteLine(objs[2]); //パラメータの名前でパラメータを指定する //str = target.PublicMethod(num2:=5, num1:=7) //と同等 str = (string) t.InvokeMember("PublicMethod", BindingFlags.InvokeMethod, null, target, new object[] {5, 7}, null, null, new string[] {"num2", "num1"}); //***** プロパティの設定と取得 **** //PublicPropertyプロパティを設定 //target.PublicProperty = 100 //と同等 t.InvokeMember("PublicProperty", BindingFlags.SetProperty, null, target, new object[] {100}); //PublicPropertyプロパティを取得 //num = target.PublicProperty //と同等 num = (int) t.InvokeMember("PublicProperty", BindingFlags.GetProperty, null, target, null); //インデクサの指定したインデックスの要素を設定 //target[1] = "two" //と同等 t.InvokeMember("Item", BindingFlags.SetProperty, null, target, new object[] {1, "two"}); //インデクサの指定したインデックスの要素を取得 //str = target[1] //と同等 str = (string) t.InvokeMember("Item", BindingFlags.GetProperty, null, target, new object[] {1}); //***** フィールドの設定と取得 ***** //PrivateFieldフィールドを設定 //target.PrivateField = 0 //と同等(ただし、通常プライベートフィールドにはアクセス不可) t.InvokeMember("PrivateField", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetField, null, target, new object[] {0}); //PrivateFieldフィールドを取得 //num = target.PrivateField //と同等(ただし、通常プライベートフィールドにはアクセス不可) num = (int) t.InvokeMember("PrivateField", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField, null, target, null); //配列StringArrayフィールドの0番目の値を設定 //target.StringArray[0] = "ゼロ" //と同等 t.InvokeMember("StringArray", BindingFlags.SetField, null, target, new object[] {0, "ゼロ"}); //配列StringArrayフィールドの0番目の値を取得 //str = target.StringArray[0] //と同等 str = (string) t.InvokeMember("StringArray", BindingFlags.GetField, null, target, new object[] {0});
上記のようにType.InvokeMemberメソッドを使う以外に、MethodInfo、ConstructorInfoクラスのInvokeメソッドを使ってメソッドやコンストラクタを呼び出したり、PropertyInfo、FieldInfoクラスのSetValue、GetValueメソッドを使ってプロパティやフィールドの値を取得、設定することもできます。なお、MemberInfoオブジェクトを取得する方法については、こちらで説明しています。
次にこれらの方法を使った簡単な例を示します。
'Imports System.Reflection 'がソースファイルの一番上に書かれているものとする 'TestClassクラスのTypeオブジェクトを取得する Dim t As Type = GetType(MyNamespace.TestClass) '***** インスタンスの作成 ***** Dim ci As ConstructorInfo = _ t.GetConstructor(New Type() {GetType(Integer)}) Dim target As Object = ci.Invoke(New Object() {5}) '***** メソッドの実行 ***** Dim mi As MethodInfo = t.GetMethod("PublicMethod", New Type() {}) Dim str As String = CStr(mi.Invoke(target, New Object() {})) '***** プロパティの設定と取得 **** Dim pi As PropertyInfo = t.GetProperty("PublicProperty") pi.SetValue(target, 1, Nothing) Dim num As Integer = CInt(pi.GetValue(target, Nothing)) '***** フィールドの設定と取得 **** Dim fi As FieldInfo = t.GetField("PrivateField", _ BindingFlags.Public Or BindingFlags.NonPublic Or _ BindingFlags.Instance) fi.SetValue(target, -1) num = CInt(fi.GetValue(target))
//using System.Reflection; //がソースファイルの一番上に書かれているものとする //TestClassクラスのTypeオブジェクトを取得する Type t = typeof(MyNamespace.TestClass); //***** インスタンスの作成 ***** ConstructorInfo ci = t.GetConstructor(new Type[] {typeof(int)}); object target = ci.Invoke(new object[] {5}); //***** メソッドの実行 ***** MethodInfo mi = t.GetMethod("PublicMethod", new Type[] {}); string str = (string) mi.Invoke(target, new object[] {}); //***** プロパティの設定と取得 **** PropertyInfo pi = t.GetProperty("PublicProperty"); pi.SetValue(target, 1, null); int num = (int) pi.GetValue(target, null); //***** フィールドの設定と取得 **** FieldInfo fi = t.GetField("PrivateField", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); fi.SetValue(target, -1); num = (int) fi.GetValue(target);
さらにインスタンスの作成は、AppDomain.CreateInstanceメソッド、Assembly.CreateInstanceメソッドや、Activator.CreateInstanceメソッド(配列を作成するときは、Array.CreateInstanceメソッド)などを使用することによっても可能です。(一般的によく使われているのは、Activator.CreateInstanceメソッドです。)
補足:ここで紹介したように、コンパイル時に型が不明であるオブジェクトをObject型変数に代入し、実行時にそのメソッドやプロパティなどを呼び出す方法を、遅延バインディングと呼びます(これに対して、コンパイル時に型が明確に宣言された変数にオブジェクトが代入される時は、事前バインディングされます)。VB.NETでは、Option StrictステートメントをOffにすることにより(あるいは、コンパイラオプションに"/optionstrict+"を指定)、暗黙の遅延バインディングを使用できますので、InvokeMemberメソッドを使ってメソッドやプロパティを呼び出す必要がなくなります。
VB.NETの暗黙の遅延バインディングにより、メソッドやプロパティを呼び出す例を以下に示します。
'Imports System.Reflection 'がソースファイルの一番上に書かれているものとする Dim num As Integer Dim str As String 'TestClassクラスのTypeオブジェクトを取得する Dim t As Type = GetType(MyNamespace.TestClass) 'TestClassのインスタンスを作成 Dim target As Object = t.InvokeMember(Nothing, _ BindingFlags.CreateInstance, _ Nothing, _ Nothing, _ New Object() {100}) 'PublicMethodメソッドを実行 num = target.PublicMethod(12) '***** プロパティの設定と取得 **** 'PublicPropertyプロパティを設定 target.PublicProperty = 100 'インデクサの指定したインデックスの要素を取得 str = target(1)
補足:構造体のインスタンスでは、オーバーロードされたメソッドの遅延バインディングの呼び出しがうまく行かないというバグがあるようです。詳しくは「マイクロソフト サポート技術情報 - 814603 [BUG] 構造体インスタンスのオーバーロードされたメソッドに対する遅延バインディングの呼び出しが期待どおりに実行されない」をご覧ください。