C Sharp/リフレクション
リフレクション
[編集]C#におけるリフレクションは、実行時に型やメンバー(プロパティ、メソッド、イベントなど)の情報を取得し、操作するための機能です。リフレクションを使うと、プログラムが実行されている時点で、型の情報を取得したり、動的にインスタンスを生成したり、メソッドやプロパティを呼び出したりできます。
例えば、特定のクラスのメソッドやプロパティの存在、名前、型、引数の情報を取得したり、その情報を使って実行したりすることが可能です。また、リフレクションを使うことで、プログラム実行時に型のインスタンスを生成し、動的にその型のメソッドやプロパティにアクセスすることもできます。
using System; using System.Reflection; public class MyClass { public int MyProperty { get; set; } public void MyMethod() { Console.WriteLine("MyMethod() called"); } } class Program { static void Main() { // クラスの型を取得 Type myClassType = typeof (MyClass); // インスタンスを作成 object myClassInstance = Activator.CreateInstance(myClassType); // プロパティのセットとゲット PropertyInfo myPropInfo = myClassType.GetProperty("MyProperty"); myPropInfo.SetValue(myClassInstance, 42); int propValue = (int) myPropInfo.GetValue(myClassInstance); Console.WriteLine("MyProperty value: " + propValue); // MyProperty value: 42 // メソッドの呼び出し MethodInfo myMethodInfo = myClassType.GetMethod("MyMethod"); myMethodInfo.Invoke(myClassInstance, null); // MyMethod() called } }
この例では、MyClass
というクラスが定義されています。Main
メソッドでは、MyClass
の型情報を取得し、リフレクションを使ってそのクラスのインスタンスを作成します。その後、GetProperty
やSetValue
、GetValue
などのリフレクションメソッドを使用して、プロパティの値を設定したり取得したりし、GetMethod
とInvoke
を使ってメソッドを呼び出しています。
このように、リフレクションを使うことで、実行時に動的にクラスやそのメンバーにアクセスできます。ただし、この方法はコンパイル時の型チェックを回避するため、適切なエラーハンドリングや型の確認が重要です。
メソッド一覧を得る
[編集]特定のクラスのメソッド一覧を取得するためには、リフレクションを使用します。以下は、特定のクラスのメソッド一覧を取得するC#の例です。
using System; using System.Reflection; public class MyClass { public void Method1() {} public int Method2(int value) { return value * 2; } public string Method3(string input) { return "Hello, " + input; } } class Program { static void Main() { Type myClassType = typeof (MyClass); // クラスのすべてのメソッドを取得 MethodInfo[] methods = myClassType.GetMethods(); Console.WriteLine("Methods in MyClass:"); foreach(var method in methods) { Console.WriteLine("Method Name: " + method.Name); // メソッドの戻り値の型 Console.WriteLine("Return Type: " + method.ReturnType.Name); // メソッドの引数 ParameterInfo[] parameters = method.GetParameters(); Console.WriteLine("Parameters:"); foreach(var param in parameters) { Console.WriteLine($" - Name: {param.Name}, Type: {param.ParameterType.Name}"); } Console.WriteLine(); } } }
- 実行結果
Methods in MyClass: Method Name: Method1 Return Type: Void Parameters: Method Name: Method2 Return Type: Int32 Parameters: - Name: value, Type: Int32 Method Name: Method3 Return Type: String Parameters: - Name: input, Type: String Method Name: GetType Return Type: Type Parameters: Method Name: ToString Return Type: String Parameters: Method Name: Equals Return Type: Boolean Parameters: - Name: obj, Type: Object Method Name: GetHashCode Return Type: Int32 Parameters:
このコードは、C#のリフレクションを使用して特定のクラス(MyClass
)のメソッド情報を取得し、それらの情報をコンソールに出力するものです。
MyClass
というクラスが定義されています。このクラスには3つのメソッドが含まれています。Program
クラスのMain
メソッドでは、MyClass
の型情報を取得しています。これにより、リフレクションを使ってMyClass
のメソッドにアクセスできるようになります。GetMethods()
メソッドを使用して、MyClass
に含まれるすべてのメソッドの情報を取得しています。これにより、MethodInfo
型の配列methods
にメソッドの情報が格納されます。foreach
ループを使用して、各メソッドの情報を取り出し、コンソールに出力しています。method.Name
でメソッド名を取得し、Console.WriteLine
を使って表示しています。method.ReturnType.Name
で戻り値の型情報を取得し、それも表示しています。method.GetParameters()
を使ってメソッドの引数情報を取得し、ParameterInfo
型の配列parameters
に格納しています。- 引数の情報(名前と型)を
foreach
ループを使って取り出し、コンソールに出力しています。
using System; using System.Reflection; class Program { static void Main() { // クラス名を指定して Type オブジェクトを取得 Type type = typeof (int); // クラス名を出力 Console.WriteLine($"クラス名:{type.Name} {{"); // フィールドの情報を取得して出力 Console.WriteLine("\t// フィールド:"); FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); foreach(var field in fields) { Console.WriteLine($"\t{field.FieldType.Name} {field.Name};"); } Console.WriteLine(); // メソッドの情報を取得して出力 Console.WriteLine("\t//メソッド:"); MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); foreach(var method in methods) { Console.Write($"\t{method.ReturnType.Name} {method.Name}("); // メソッドの引数を出力 ParameterInfo[] parameters = method.GetParameters(); for (int i = 0; i < parameters.Length; i++) { Console.Write($"{parameters[i].Name} {parameters[i].ParameterType.Name}"); if (i < parameters.Length - 1) { Console.Write(", "); } } Console.WriteLine(");"); } Console.WriteLine("}"); } }
- 実行結果
クラス名:Int32 { // フィールド: Int32 m_value; //メソッド: Int32 CompareTo(value Object); Int32 CompareTo(value Int32); Boolean Equals(obj Object); Boolean Equals(obj Int32); Int32 GetHashCode(); String ToString(); String ToString(format String); String ToString(provider IFormatProvider); String ToString(format String, provider IFormatProvider); Boolean TryFormat(destination Span`1, charsWritten Int32&, format ReadOnlySpan`1, provider IFormatProvider); Boolean TryFormat(utf8Destination Span`1, bytesWritten Int32&, format ReadOnlySpan`1, provider IFormatProvider); TypeCode GetTypeCode(); Boolean System.IConvertible.ToBoolean(provider IFormatProvider); Char System.IConvertible.ToChar(provider IFormatProvider); SByte System.IConvertible.ToSByte(provider IFormatProvider); Byte System.IConvertible.ToByte(provider IFormatProvider); Int16 System.IConvertible.ToInt16(provider IFormatProvider); UInt16 System.IConvertible.ToUInt16(provider IFormatProvider); Int32 System.IConvertible.ToInt32(provider IFormatProvider); UInt32 System.IConvertible.ToUInt32(provider IFormatProvider); Int64 System.IConvertible.ToInt64(provider IFormatProvider); UInt64 System.IConvertible.ToUInt64(provider IFormatProvider); Single System.IConvertible.ToSingle(provider IFormatProvider); Double System.IConvertible.ToDouble(provider IFormatProvider); Decimal System.IConvertible.ToDecimal(provider IFormatProvider); DateTime System.IConvertible.ToDateTime(provider IFormatProvider); Object System.IConvertible.ToType(type Type, provider IFormatProvider); Int32 System.Numerics.IBinaryInteger<System.Int32>.GetShortestBitLength(); Int32 System.Numerics.IBinaryInteger<System.Int32>.GetByteCount(); Boolean System.Numerics.IBinaryInteger<System.Int32>.TryWriteBigEndian(destination Span`1, bytesWritten Int32&); Boolean System.Numerics.IBinaryInteger<System.Int32>.TryWriteLittleEndian(destination Span`1, bytesWritten Int32&); Type GetType(); Object MemberwiseClone(); Void Finalize(); }
このコードは、C#のリフレクションを使用して、与えられたクラスの情報を取得し、そのフィールドとメソッドをコンソールに出力するものです。以下、コードの解説です。
using System;
とusing System.Reflection;
は、必要な名前空間をインポートしています。static void Main()
メソッドはプログラムのエントリーポイントです。ここでクラスの情報を取得し、出力を行います。Type type = typeof(int);
の部分で、typeof
キーワードを使用して、指定した型 (int
の場合) のType
オブジェクトを取得しています。この部分を、調査したいクラスの型に置き換えることで、そのクラスの情報を取得できます。Console.WriteLine($"クラス名:{type.Name} {{");
は、取得したクラスの名前をコンソールに出力しています。ここでクラスの開始を示す{
も表示しています。FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
は、指定したクラスのフィールド情報を取得しています。BindingFlags
は、取得するフィールドの種類を指定しています。foreach(var field in fields)
ループでは、取得したフィールドの情報を一つずつ取り出して、その型と名前をコンソールに出力しています。- 同様に、メソッドの情報を取得しています。
MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
でメソッド情報を取得し、それぞれのメソッドの戻り値の型と名前、引数の情報をコンソールに出力しています。 - 最後に、
}
でクラスの終了を示しています。
あるクラスからObjectまで親クラスを遡る
[編集]C#で特定のクラスから親クラスを Object
まで遡るコードをリフレクションを使って書くことができます。以下はその例です。
using System; class Program { static void Main() { Type type = typeof (int); Console.WriteLine($"クラス: {type.Name}"); Type currentType = type; // 親クラスが Object になるまでループで親クラスを表示 while (currentType.BaseType != null) { Console.WriteLine($"親クラス: {currentType.BaseType.Name}"); currentType = currentType.BaseType; } } }
- 実行結果
クラス: Int32 親クラス: ValueType 親クラス: Object
このコードでは、int
の親クラスを Object
まで遡って表示します。
typeof
演算子は、指定された型の Type
オブジェクトを取得します。BaseType
プロパティは、その型の直接の親クラスを返します。このプロパティを使って親クラスを取得し、Object
まで遡るまでループを繰り返し、各親クラスの名前をコンソールに出力します。