「TIPS:文字列で指定したクラスのインスタンスを作成するには?」では、文字列によるクラスのインスタンス化について解説した。本稿では、メソッドの名前を文字列で指定して、そのメソッドを動的に呼び出す方法について解説する。
MethodInfoクラスのInvokeメソッドによるメソッドの実行
前掲のTIPSと同様に、文字列によりメソッドを呼び出す場合にも、まずは呼び出そうとしているメソッドを含んでいるクラスのTypeオブジェクトを取得する。もしそのクラスのインスタンスがすでに作成済みなら、GetTypeメソッドにより、そのTypeオブジェクトを取得できる(以降のコード例はC#の場合。VB.NETの場合は後掲のサンプル・プログラムを参照してほしい)。
SomeClass sc = new SomeClass();
Type t = sc.GetType();
次に、呼び出そうとするメソッドの名前をパラメータに指定して、取得したTypeオブジェクトのGetMethodメソッドを呼び出す。このメソッドは、MethodInfoクラス(System.Reflection名前空間)のオブジェクトを返す。MethodInfoクラスは特定のメソッドについての情報を表すクラスである。
MethodInfo mi = t.GetMethod("呼び出したいメソッド名");
最後に、MethodInfoオブジェクトのInvokeメソッドを呼び出せば、メソッドを実行することができる。Invokeメソッドは戻り値をobject型として返すので、メソッドに戻り値がある場合には、通常キャストが必要となる。
object o = mi.Invoke(sc, new object[] { パラメータ…… } );
Invokeメソッドの第1パラメータには、呼び出したいメソッドを含むインスタンスを指定する。そのメソッドが静的メソッドならばnull(VB.NETの場合はNothing)を指定する。また、第2パラメータには呼び出したいメソッドに渡すパラメータをobject型の配列で指定する。メソッドがパラメータを取らなければnull(Nothing)を指定する。
文字列で指定したメソッドを呼び出すサンプル・プログラム
以下に、Invokeメソッドを使用したサンプル・プログラムを示す。ここでは、文字列(Stringクラスのインスタンス)に対して、Remove、Substring、IndexOfの3つのメソッドを、メソッド名により実行している。
// methodinvoke.cs
using System;
using System.Reflection;
public class MethodInvoke {
static void Main() {
string msg = "メリー・クリスマス";
Type stringType = msg.GetType();
// Type stringType = typeof(string); // これでもOK
// 以下はmsg.Remove(0, 4)と同じ
//
MethodInfo mi1 = stringType.GetMethod("Remove");
string removed
= (string)mi1.Invoke(msg, new object[] { 0, 4 });
Console.WriteLine(removed); // 出力:クリスマス
// 以下はmsg.Substring(4)と同じ
//
// オーバーロードされたメソッドがあるため
// パラメータの型によりメソッドを特定
MethodInfo mi2 = stringType.GetMethod(
"Substring", new Type[] { typeof(int) });
string substring
= (string)mi2.Invoke(msg, new object[] { 4 });
Console.WriteLine(substring); // 出力:クリスマス
// 以下はmsg.IndexOf("クリ")と同じ
//
// オーバーロードされたメソッドがあるため
// パラメータの型によりメソッドを特定
MethodInfo mi3 = stringType.GetMethod(
"IndexOf", new Type[] { typeof(string) });
int index = (int)mi3.Invoke(msg, new object[] { "クリ" });
Console.WriteLine(index); // 出力:4
}
}
// コンパイル方法:csc methodinvoke.cs
methodinvoke.csのダウンロード
' methodinvoke.vb
Imports System
Imports System.Reflection
Public Class MethodInvoke
Shared Sub Main()
Dim msg As String = "メリー・クリスマス"
Dim stringType As Type = msg.GetType()
' Dim stringType As Type = GetType(string) ' これでもOK
' 以下はmsg.Remove(0, 4)と同じ
'
Dim mi1 As MethodInfo = StringType.GetMethod("Remove")
Dim removed As String = _
CType(mi1.Invoke(msg, New Object() { 0, 4 }), String)
Console.WriteLine(removed) ' 出力:クリスマス
' 以下はmsg.SubString(4)と同じ
'
' オーバーロードされたメソッドがあるため
' パラメータの型によりメソッドを特定
Dim mi2 As MethodInfo = StringType.GetMethod( _
"Substring", New Type() { GetType(Integer) })
Dim subString As string = _
CType(mi2.Invoke(msg, New Object() { 4 }), String)
Console.WriteLine(subString) ' 出力:クリスマス
' 以下はmsg.IndexOf("クリ")と同じ
'
' オーバーロードされたメソッドがあるため
' パラメータの型によりメソッドを特定
Dim mi3 As MethodInfo = StringType.GetMethod( _
"IndexOf", New Type() { GetType(string) })
Dim index As Integer = _
CType(mi3.Invoke(msg, New Object() { "クリ" }), Integer)
Console.WriteLine(index) ' 出力:4
End Sub
End Class
' コンパイル方法:vbc methodinvoke.vb
methodinvoke.vbのダウンロード
StringクラスのRemoveメソッドは必ず2つの整数型のパラメータを取るが、SubstringメソッドとIndexOfメソッドについては、オーバーロードされたメソッドが存在する。例えばSubstringメソッドには、パラメータとして1つの整数型を取るものと、2つの整数型を取るものがある。
このように、文字列により呼び出そうとしているメソッドがオーバーロードされている場合には、GetMethodメソッドによりMethodInfoオブジェクトを取得する際に、目的とするメソッドのパラメータを第2パラメータで指定して、どのメソッドかを厳密に指定する必要がある。ここには、各パラメータの型のTypeオブジェクトの配列を指定する。
次のコードは、1つの整数型のパラメータを取るSubstringメソッドに関するMethodInfoオブジェクトを取得している。
MethodInfo mi = t.GetMethod(
"Substring", new Type[] { typeof(int) });
2つの整数型のパラメータを取るSubstringメソッドのMethodInfoオブジェクトは次のようにして取得する。
MethodInfo mi = t.GetMethod(
"Substring", new Type[] { typeof(int), typeof(int) });
なお、メソッドではなくプロパティを文字列で指定して呼び出す場合には、TypeクラスのGetPropertyメソッドや、プロパティに関する情報を表すPropertyInfoクラス(System.Reflection名前空間)を利用すればよい。
カテゴリ:クラス・ライブラリ 処理対象:リフレクション
使用ライブラリ:Typeクラス(System名前空間)
使用ライブラリ:MethodInfoクラス(System.Reflection名前空間)
関連TIPS:文字列で指定したクラスのインスタンスを作成するには?
関連TIPS:メソッドやプロパティの有無を確認して呼び出すには?
Copyright© Digital Advantage Corp. All Rights Reserved.