3秒でわかる「リフレクション」【UnityC#】
リフレクションとは
メタデータを使ってクラスやメソッドの情報にアクセスすることです!
メタデータは、クラス名やメソッド名、変数などの、プログラムデータに関する情報のことです。
リフレクションを使うことで、メタデータの取得はもちろん、メタデータからクラスや関数を呼び出すこともできます。
アセンブリからデータを呼び出すこともできます!すごい!
リフレクションプローブ(Reflection Prove)とは無関係です。
今回は、他クラスのメタデータの取得とメソッドの呼び出しを試してみます。
メタデータを見てみる
まずはメタデータを取得する対象のクラスを定義します。
public class TestClass { public int num; private int numPrivate; public void Method () { } private void MethodPrivate () { } }
実際にメタデータを取得するスクリプトを書きます!
using UnityEngine; using System.Reflection; using System; public class TestReflection : MonoBehaviour { private BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly; private void Start () { Test(); } private void Test () { Type type = Type.GetType("TestClass"); //メンバーのデータ Debug.Log("-----Member-----"); foreach(var i in type.GetMembers(bindingFlags)) { Debug.Log(i); } //変数のデータ Debug.Log("-----field-----"); foreach(var i in type.GetFields(bindingFlags)) { Debug.Log(i); } //メソッドのデータ Debug.Log("-----Method-----"); foreach(var i in type.GetMethods(bindingFlags)) { Debug.Log(i); } } }
ここでのポイント
リフレクションをするために含めます。
using System.Reflection; using System;
「TestClass」クラスを取得します。
Type type = Type.GetType("TestClass");
これらのメソッドでメタデータを取得します。
type.GetMembers(); type.GetFields(); type.GetMethods();
type.Get~系のメソッドの引数に入れることで、アクセスする対象を決めます。
private BindingFlags bindingFlags =
BindingFlags.Instance |
BindingFlags.Static |
BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.DeclaredOnly;
「Instance」「Static」はどちらかがなければいけなく、また、「Public」「NonPublic」もどちらかがなければいけません。
「Instance」「Static」「Public」「NonPublic」は名前から意味が分かると思います。
「DeclaredOnly」は対象にするクラスのみをアクセスする、という意味です。
BindingFlagsについて詳しく知りたい方は以下のページを見てください!
docs.microsoft.com
実行する
うまく取れていそうですね!
メンバーの.ctor()はコンストラクタです!
次はメソッドを実際に呼び出してみます。
メソッドを呼び出してみる
他クラスからSumメソッドを呼び出して足し算をしてみます!
TestClassを書き換える
Sumメソッドを定義します。
public class TestClass { public int Sum (int a,int b) { return a + b; } }
TestReflectionを書き換える
TestClassのSum()メソッドをSum()メソッドでラップします!
using UnityEngine; using System.Reflection; using System; public class TestReflection : MonoBehaviour { private Type[] argType = new Type[] { typeof(Int32),typeof(Int32) }; private BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly; private void Start () { Debug.Log(Sum(1,3)); } private int Sum (int a,int b) { object[] args = { a,b }; Type type = Type.GetType("TestClass"); object tmp = Activator.CreateInstance(type); return (int)type.GetMethod("Sum",bindingFlags,null,argType,null).Invoke(tmp,args); } }
ここでのポイント
「TestClass」のインスタンス生成
object tmp = Activator.CreateInstance(type);
メソッドの引数を定義
private Type[] argType = new Type[] { typeof(Int32),typeof(Int32) };
メソッドを取得してリターン
private int Sum (int a,int b) { object[] args = { a,b }; Type type = Type.GetType("TestClass"); object tmp = Activator.CreateInstance(type); return (int)type.GetMethod("Sum",bindingFlags,null,argType,null).Invoke(tmp,args); }
GetMethod()を使用してTestClassのSum()メソッドを取得しています。
ここでは1、2、4個目の引数を扱っています。3、5個目はnullでOKです。
内容としては、
[1]メソッドの名前
[2]BindingFlags
[3](Binderクラス)
[4]引数の型
[5](ParameterModifier構造体)
になっています。
実行する
これで関数呼び出し完了です!