スポンサーリンク
UnityUnityメモ

Unityでリフレクションを活用!柔軟で拡張性の高いスクリプトを作る方法

Unity

【Unity】Reflection(リフレクション)の使い方完全ガイド|柔軟なスクリプト設計術

1. はじめに

Unityで開発をしていると、「このメソッドを動的に呼び出したい」「インスペクタ上から任意の関数を実行できたら便利なのに…」と思うことはありませんか? そんなときに役立つのがReflection(リフレクション)です。

リフレクションを使うと、プログラムの実行中にクラスの型情報を取得し、通常ではアクセスできないメソッドや変数に動的に触れることができます。例えば、private関数を外部から呼び出したり、Unity内部の隠されたAPIを利用したりすることも可能になります。

「なんだか難しそう…」と思うかもしれませんが、実は基本さえ押さえれば便利に活用できます。特にエディタ拡張ツール開発では、作業を効率化できる強力な武器になりますよ。

この記事では、UnityでのReflectionの基本から応用まで、わかりやすく解説していきます。 「もっと柔軟にスクリプトを設計したい」「エディタを自分用に強化したい」という方は、ぜひ最後まで読んでみてくださいね!


2. Reflectionの概要と注意点

まずは、Reflectionがそもそもどんな機能なのかを簡単に整理しておきましょう。

2-1. Reflectionとは?

Reflection(リフレクション)は、C#の仕組みのひとつで、実行中のプログラムからオブジェクトの型情報を取得し、そのメソッドや変数に動的にアクセスできる機能です。

たとえば、クラスに定義されている関数の一覧を取得したり、文字列からメソッドを呼び出したりといったことが可能になります。通常のコードでは触れないprivate関数やUnity内部のinternalクラスにもアクセスできるのが大きな特徴です。

2-2. 主な利用目的

  • 非公開メソッドや変数にアクセスできる → デバッグやツール制作で役立ちます。
  • Unity内部の隠し機能を呼び出せる → たとえば、アニメーションウィンドウの内部操作やエディタ専用機能に触れることが可能です。
  • 柔軟で拡張性の高いスクリプト設計 → 任意のメソッドを文字列から実行できるため、ユーザーが自由に処理を選択できる仕組みを作れます。

2-3. 注意点とデメリット

便利な一方で、Reflectionにはいくつかのデメリットもあります。

  1. パフォーマンスへの影響 Reflectionは仕組み上処理が重く、ランタイムで多用するとフレームレート低下の原因になります。 → ゲームプレイ中よりも、ツールやエディタ拡張での利用がおすすめです。
  2. Unityバージョン依存 Unityの内部仕様が変わると、Reflectionでアクセスしていた処理が使えなくなることがあります。アップデート時には動作検証が必須です。
  3. コードの可読性低下 文字列でメソッドを指定する場合、タイポやリファクタリングに弱い点があります。

2-4. デバッグ効率を高めるには

Reflectionを活用すると、内部情報を引き出して通常では見えないログを扱うこともできます。ただ、標準のコンソールだけでは管理が難しいことも…。 そんなときにおすすめなのが、Editor Console Proです。

ログの検索・フィルタリングが圧倒的にやりやすくなるので、Reflectionと組み合わせると「内部APIを使った高度なデバッグ」もスムーズになりますよ。


3. Reflectionを使った応用例:インスペクタ上でメソッドを選択・実行する

UnityでUIのボタンを作るときに、インスペクタから「どの関数を呼び出すか」を選択できますよね。 実は、この仕組みをReflectionとカスタムエディタを組み合わせることで、任意のコンポーネントに定義された関数をインスペクタから実行できるようにできます。

3-1. 基本フロー

この機能を実現する流れは以下の通りです。

  1. カスタムエディタを作成する – 例:TargetClassEditor を作成し、対象クラス TargetClass のインスペクタをカスタム。
  2. アタッチされたコンポーネントを取得するm_Target.TargetObject.GetComponents<MonoBehaviour>() でスクリプトを列挙。
  3. メソッドリストを収集するGetType()GetMethods() を呼び出し、 BindingFlags.Instance | BindingFlags.Public で「インスタンス・public・引数なし」のメソッドに絞る。
  4. インスペクタに表示するEditorGUILayout.Popup() を使ってメソッド名のリストをポップアップで表示。 選択したメソッド名を変数に保持しておく。
  5. メソッドを実行する – 選ばれたメソッドを MethodInfo.Invoke()SendMessage() で呼び出す。

3-2. 実装例(概要)


// メソッドを収集するサンプルコード
var methods = component.GetType()
    .GetMethods(BindingFlags.Instance | BindingFlags.Public)
    .Where(m =&gt; m.GetParameters().Length == 0) // 引数なしに限定
    .Select(m =&gt; m.Name)
    .ToArray();

こうして集めたメソッド名をインスペクタに表示し、選択した関数を呼び出せば、 「インスペクタから任意の関数を実行できる便利な仕組み」が完成します。

3-3. 実装時の注意点

  • 実行対象の変数は [SerializeField] をつけてシーン切り替え時にリセットされないようにする。
  • メソッド呼び出しはパフォーマンスに影響するため、ツール用途やエディタ拡張に留めるのがおすすめ。

3-4. もっと手軽にやりたい方へ

ここまで紹介した方法は「自作して理解を深める」には最適ですが、ゼロから作るのは大変…。 そんなときは、Odin Inspector & Serializer を使えば、インスペクタからメソッド実行やUIカスタムがノーコードで即利用可能になります。

Reflectionの知識を学んだ上で導入すれば、より一層便利に活用できますよ✨


4. Reflectionの具体的な使い方(基本要素と手順)

ここからは、実際にReflectionを使うための基本的な書き方を解説します。 ポイントは 型情報を取得 → メソッドや変数を調べる → 必要なら実行・変更する という流れです。

4-1. 型情報とインスタンスの取得

  1. クラス情報を取得する // フルネーム(ネームスペース込みのクラス名)を指定 Type type = Type.GetType("MyNamespace.MyClass");
  2. 別アセンブリにあるクラスを指定する場合 Type type = Type.GetType("MyNamespace.MyClass, Assembly-CSharp");
  3. インスタンスを生成する object instance = Activator.CreateInstance(type);
  4. 親クラスを取得する Type baseType = type.BaseType;

4-2. メソッドを取得して実行する

メソッドの情報は GetMethod() または GetMethods() で取得します。


// メソッドを単体で取得
MethodInfo method = type.GetMethod("Hello", BindingFlags.Instance | BindingFlags.Public);

// メソッドを実行(引数なし)
method.Invoke(instance, null);

// 引数ありの場合
method.Invoke(instance, new object[] { 100, "Unity" });

また、メソッドの引数や戻り値の型を調べることも可能です。


// 引数リストを確認
ParameterInfo[] parameters = method.GetParameters();

// 戻り値の型を確認
Type returnType = method.ReturnType;

4-3. フィールド(変数)の取得と操作

変数を操作したい場合は GetField()GetFields() を使用します。


// フィールドを取得
FieldInfo field = type.GetField("myValue", BindingFlags.Instance | BindingFlags.NonPublic);

// 値を取得
object value = field.GetValue(instance);

// 値を変更
field.SetValue(instance, 999);

// フィールドの型を確認
Type fieldType = field.FieldType;

4-4. BindingFlagsの主な使い方

Reflectionでは、取得対象を制御するためにBindingFlagsを指定します。

BindingFlags意味補足
Instanceインスタンスメンバーを対象にする
Publicpublic メンバーを取得
NonPublicprivate / protected を含むただし親クラスの private は取得不可
DeclaredOnly宣言クラスのメンバーのみ外すと親クラスも含む
Staticstatic メンバーを対象にする
FlattenHierarchy親クラスの static を含むprivate は対象外

このようにBindingFlagsを組み合わせることで、欲しいメンバーだけを効率的に取り出せます。


5. Reflection活用時の実践Tips

ここからは、Reflectionを使うときに知っておくと便利なテクニックを紹介します。 「とりあえず動かす」だけでなく、効率的に運用するためのコツを覚えておきましょう。

5-1. BindingFlagsをうまく使い分ける

Reflectionで一番大事なのは、欲しい対象だけを正しく絞り込むことです。 たとえば、publicインスタンスメソッドだけ取得したい場合は以下のようにします。


var methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public);

逆に、private変数を確認したいときは NonPublic を指定する必要があります。


var field = type.GetField("hiddenValue", BindingFlags.Instance | BindingFlags.NonPublic);

5-2. LINQと組み合わせる

メソッド一覧を取得した後に、LINQでフィルタリングするとコードがすっきりします。 たとえば「引数なしメソッドだけを抽出」する例はこんな感じです。


var targetMethods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public)
    .Where(m =&gt; m.GetParameters().Length == 0)
    .Select(m =&gt; m.Name)
    .ToArray();

5-3. 匿名型を使ってインデックスと名前を同時管理

インスペクタで「メソッド名とインデックス」を同時に扱いたいときは、匿名型を使うと便利です。


var methodList = type.GetMethods(BindingFlags.Instance | BindingFlags.Public)
    .Select((m, index) =&gt; new { Name = m.Name, Index = index })
    .ToList();

これで「インスペクタに表示する名前」と「選択インデックス」をまとめて扱えるようになります。

5-4. キャッシュしてパフォーマンスを改善

Reflectionはどうしても処理が重いので、毎フレーム実行はNGです。 一度取得したメソッドやフィールドはキャッシュして再利用しましょう。


// 悪い例(毎回GetMethod)
void Update() {
    var method = type.GetMethod("DoSomething");
    method.Invoke(instance, null);
}

// 良い例(Startでキャッシュしておく)
MethodInfo cachedMethod;

void Start() {
    cachedMethod = type.GetMethod("DoSomething");
}

void Update() {
    cachedMethod.Invoke(instance, null);
}

5-5. 実用的な活用シーン

  • エディタ拡張ツールで「任意のメソッドをGUIから実行」
  • デバッグ用に「非公開変数をモニタリング」
  • ユーザー入力に応じて「関数を文字列から呼び出す」

こうした場面でReflectionを活用すると、Unity開発の幅が大きく広がりますよ。


6. まとめ

今回は、UnityでのReflection(リフレクション)の基本から応用までを解説しました。 Reflectionを使うと、普段は触れないメソッドや変数にアクセスできたり、インスペクタを便利にカスタマイズできたりと、開発の自由度がグッと広がります。

ただし、ランタイムで多用するとパフォーマンスに影響したり、Unityのバージョンアップで動かなくなる可能性もあるので、主にエディタ拡張やツール開発での利用がオススメです。

「もっと効率よく開発を進めたい」「自作するのは大変だけどインスペクタを便利にしたい」という方は、アセットを導入するのも良い選択です。特に以下の2つは多くの開発者に支持されている鉄板ツールですよ。

これらを組み合わせれば、Reflectionを学んだ知識をさらに強力に活かせるはずです。 ぜひ、自分のUnity開発に取り入れてみてくださいね✨


おすすめ書籍

Reflectionの知識を深めると同時に、UnityやC#の基礎をしっかり学んでおくと応用力がぐっと高まります。 以下の書籍は、今回のテーマと相性が良いおすすめの参考書です。

これらの本を手元に置いておくと、「Reflectionでやりたいことが出てきたけどC#の基礎文法を復習したい!」といった場面でもすぐに解決できます。 UnityとC#をバランス良く学んで、さらに効率的な開発を目指しましょう✨


あわせて読みたい

Reflectionを理解すると、スクリプト設計やデータ管理の知識とあわせて活用するとさらに便利になります。 以下の記事もあわせて読むと、Unity開発の理解がより深まりますよ。


よくある質問(FAQ)

Q
Reflectionはゲーム本番で使っても大丈夫?
A

A. もちろん使えますが、毎フレーム実行する処理には向いていません。 Reflectionは処理が重いので、ランタイムのゲームロジックに組み込むとフレームレート低下の原因になります。 おすすめは「エディタ拡張」「デバッグツール」「一時的な初期化処理」などでの利用です。

Q
内部APIをReflectionで呼び出すのは違法?
A

A. 違法ではありませんが、Unityのサポート外となる点に注意しましょう。 Unityがバージョンアップした際に内部仕様が変わると、動かなくなるリスクがあります。 「商用ゲームの本番処理に依存させる」のではなく、開発効率を高めるツール用途で使うのが安心です。

Q
Odin InspectorとReflectionの違いは?
A

A. ReflectionはC#の標準機能で、開発者が自分で仕組みを作る必要があります。 一方、Odin Inspector は、Reflectionを内部で活用している高機能ツールで、インスペクタ拡張やデータ管理がノーコードで簡単にできます。 「学習目的ならReflection、自作を省略して効率化したいならOdin」という住み分けがおすすめです。

※当サイトはアフィリエイト広告を利用しています。リンクを経由して商品を購入された場合、当サイトに報酬が発生することがあります。

※本記事に記載しているAmazon商品情報(価格、在庫状況、割引、配送条件など)は、執筆時点のAmazon.co.jp上の情報に基づいています。
最新の価格・在庫・配送条件などの詳細は、Amazonの商品ページをご確認ください。

スポンサーリンク