【.NET】リフレクション入門

# リフレクションとは？
普段業務でC#を使用していますが、.NETフレームワークにはリフレクションなる機能が存在しているらしい。知らなかった😩

愛用しているPerplexity様に、「C#マスターになるためには必須の知識です」とアドバイスいただきました。

**これは入門するしかない！**

ということで、まずは公式ドキュメントを見てみましょう。
> System.Reflection 名前空間内のクラスを System.Type と共に使用すると、読み込まれたアセンブリについての情報、およびそのアセンブリ内に定義されているクラス、インターフェイス、値型 (つまり、構造体と列挙) などの型を取得できます。 また、リフレクションを使用すると、実行時に型インスタンスを作成したり、作成した型インスタンスを呼び出したり、アクセスしたりできます。

※リンクは記事の最後に載せてます。

名前空間で言うと`System.Reflection`に存在する機能が該当します。

大きく分けて以下の2点が実現可能みたいですね。
- アセンブリの情報取得(アセンブリ内に定義されてれるオブジェクトの型取得)
- 実行時に型インスタンスの生成、および作成した型へのアクセス

なるほど…

物は試しということでとりあえず使ってみることにします。

# アセンブリの情報取得
まずは、アセンブリ情報を格納している`System.Reflection.Asembly`を見てみます。

公式ドキュメントの実装例をそのままお借りします。
```c#
using System;
using System.Reflection;

// object型のアセンブリ情報を取得して出力
Assembly a = typeof(object).Module.Assembly;
Console.WriteLine(a.FullName);
```
👇出力内容
```
System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e
```
カンマ区切りで
"アセンブリ名, バージョン, カルチャ, 公開キートークン"
が取得できていることが確認できますね。

# 特定の型のコンストラクター情報を取得
コンストラクタがたくさんあるクラスってややこしいですよね。
それもリフレクションを使えば一覧で情報を取得できます。

`System.String`のコンストラクタを一覧で見てみましょう。
```c#
using System;
using System.Reflection;

// GetConstructor()を使ってstringのコンストラクタ情報を取得
// https://learn.microsoft.com/ja-jp/dotnet/api/system.type.getconstructor?view=net-9.0
ConstructorInfo[] constructorInfos = typeof(string).GetConstructors();

// 一覧で出力
foreach (ConstructorInfo info in constructorInfos)
{
    Console.WriteLine(info);
}
```

👇出力内容
```
Void .ctor(Char[])
Void .ctor(Char[], Int32, Int32)
Void .ctor(Char*)
Void .ctor(Char*, Int32, Int32)
Void .ctor(SByte*)
Void .ctor(SByte*, Int32, Int32)
Void .ctor(SByte*, Int32, Int32, System.Text.Encoding)
Void .ctor(Char, Int32)
Void .ctor(System.ReadOnlySpan`1[System.Char])
```
ややこしいコンストラクタの引数が一目瞭然ですね。
`.ctor`はコンストラクタを表すそうです。

# 特定の型のpublicメンバー情報を取得
続いては、`System.Reflection.MemberInfo`を使ってみます。
プログラム実行中に任意の型のpublicメンバーを取得できます。

`object`に定義されているメンバーを取得してみます。
```c#
using System;
using System.Reflection;

// Type.GetMembers()を使ってMemberInfoを取得
// http://learn.microsoft.com/ja-jp/dotnet/api/system.type.getmembers?view=net-9.0
MemberInfo[] memberInfos = typeof(object).GetMembers();

// 一覧で出力
foreach (MemberInfo member in memberInfos)
{
    Console.WriteLine(member.Name);
}
```
👇出力内容
```
GetType
ToString
Equals
Equals
ReferenceEquals
GetHashCode
.ctor
```
`System.Object`クラスに定義されているpublicメンバーが取得できました👏
ちなみにpublicメンバーという指定だけではなく、同じ方法でメソッド、フィールド、プロパティを分けて取得することもできます。

使用するメソッドは下記の通り。
| 取得したい情報 | 使用するメソッド |
|:-:|:-:|
|pulicメンバー|GetMenbers()|
|メソッド|GetMethods()|
|フィールド|GetFields()|
|プロパティ|GetProperties()|

# 代表的な機能
最後に、リフレクションの代表的な機能をまとめておきます。

- **Assembly**
アセンブリ定義の読み込み、アセンブリからの型検索、インスタンス生成
- **Module**
モジュール内のクラスなどの探索（グローバルメソッドや固有の非グローバルメソッドも可）
- **ConstructorInfo**
コンストラクターの名前、パラメーター、アクセス修飾子、および実装詳細を探索
- **MethodInfo**
メソッドの名前、戻り値の型、パラメータ、アクセス修飾子、および実装の詳細を検出
- **FieldInfo**
フィールドの名前、アクセス修飾子、実装の詳細の検出、および値の取得・設定
- **EventInfo**
イベントハンドラーの名前、データ型、カスタム属性、宣言型等の探索、およびイベントの追加・削除
- **PropertyInfo**
プロパティの名前、データ型、宣言型、リフレクションされた型、読み取り専用・書き込み専用のどちらか等の探索、および値の取得・設定
- **ParameterInfo**
パラメーターの名前、データ型、入出力どちらか、メソッドシグネチャ内のパラメータの位置等の探索
- **CustumAttributeInfo**
`MetadataLoadContext`またはリフレクション専用のコンテキスト (.NET Framework) で作業する際に、カスタム属性に関する情報を検出する

# 公式ドキュメント
https://learn.microsoft.com/ja-jp/dotnet/fundamentals/reflection/reflection