こんにちは、Unityエンジニアのオオバです。
UnityというかC#の話です。
Unityの隠蔽関数を調べたい時がよくあります。
そんな時リフレクションを使って関数や変数を調べることが多いと思います。
リフレクション使用時にBindingFlags
を使うわけですが結構種類があり、どれを使ってよいのか忘れてしまうので整理しておこうと思います。
公式リファレンスはこちら BindingFlags 列挙型 (System.Reflection) | Microsoft Docs
※本記事はタイトルの通り関数リフレクションに絞った記事です
👉DOTweenの教科書を読んでUnityアニメーションをプログラミングしてみよう!
リフレクションを使って関数列挙する
簡単に説明すると、Type型に対しGetMethods関数
を実行して関数情報を保持したデータMethodInfo
の配列を取得できます。
GetMethods関数の引数
に先のBindingFlags
を指定することで取得する関数を調整することが出来ます。
ここからは、確認用として以下のサンプルクラスを使って検証します。
指定クラス階層のPublicメンバを取得
親クラス
検証コード
var methodInfos = typeof(SampleClass)
.GetMethods (
BindingFlags.Instance |
BindingFlags.Static |
BindingFlags.Public |
BindingFlags.DeclaredOnly
);
foreach(var method in methodInfos) { Debug.Log (method.Name); }
- BindingFlags.Instance
- BindingFlags.Static
- BindingFlags.Public
- BindingFlags.DeclaredOnly
この4つを指定することで取得できます。
出力
get_StatciPublicProp
set_StatciPublicProp
get_MemberPublicProp
set_MemberPublicProp
StaticPublicMethod
MemberPublicMethod
親クラスのPublicメンバを含めて取得
取得メンバの階層を制限するBindingFlags.DeclaredOnly
を外し、代わりにBindingFlags.FlattenHierarchy
を追加します。
BindingFlags.FlattenHierarchy
は、親階層のPrivateクラスメンバ以外を検索の対象に加えます。
すると以下のように親クラスのPublicメンバを含めたメンバリストを取得することが出来ます。
検証コード
var methodInfos = typeof(SampleClass)
.GetMethods (
BindingFlags.Instance |
BindingFlags.Static |
BindingFlags.Public |
BindingFlags.FlattenHierarchy
);
foreach(var method in methodInfos) { Debug.Log (method.Name); }
出力
get_StatciPublicProp
set_StatciPublicProp
get_MemberPublicProp
set_MemberPublicProp
StaticPublicMethod
MemberPublicMethod
get___StatciPublicProp
set___StatciPublicProp
get___MemberPublicProp
set___MemberPublicProp
__StaticPublicMethod
__MemberPublicMethod
Equals
GetHashCode
GetType
ToString
ReferenceEquals
ちなみに、出力リスト内の以下の関数は、SampleClass, SuperSampleにも定義はありません。こちらは、C#の仕様上System.Objectクラスを自動的に継承することになるため、System.Objectクラスに定義された関数が出力されているということになります。
Equals
GetHashCode
GetType
ToString
ReferenceEquals
指定クラス階層の非Publicメンバを取得
BindingFlags.PublicをBindingFlags.NonPublic
に変更します。
検証コード
var methodInfos = typeof(SampleClass)
.GetMethods (
BindingFlags.Instance |
BindingFlags.Static |
BindingFlags.NonPublic |
BindingFlags.DeclaredOnly
);
foreach(var method in methodInfos) { Debug.Log (method.Name); }
出力
get_StaticPrivateProp
set_StaticPrivateProp
get_StaticInternalProp
set_StaticInternalProp
get_StaticProtectedProp
set_StaticProtectedProp
get_MemberInternalProp
set_MemberInternalProp
get_MemberPrivateProp
set_MemberPrivateProp
get_MemberProtectedProp
set_MemberProtectedProp
StaticPrivateMethod
StaticProtectedMethod
StaticInternalMethod
MemberPrivateMethod
MemberProtectedMethod
MemberInternalMethod
非Publicメンバ取得の落とし穴
親クラスを含めた非Publicメンバを取得するためにBindingFlags.DeclaredOnly
指定を外し、BindingFlags.FlattenHierarchy
を追加してみます。
検証コード
var methodInfos = typeof(SampleClass)
.GetMethods (
BindingFlags.Instance |
BindingFlags.Static |
BindingFlags.NonPublic |
BindingFlags.FlattenHierarchy
);
foreach(var method in methodInfos) { Debug.Log (method.Name); }
出力
get_StaticPrivateProp
set_StaticPrivateProp
get_StaticInternalProp
set_StaticInternalProp
get_StaticProtectedProp
set_StaticProtectedProp
get_MemberInternalProp
set_MemberInternalProp
get_MemberPrivateProp
set_MemberPrivateProp
get_MemberProtectedProp
set_MemberProtectedProp
StaticPrivateMethod
StaticProtectedMethod
StaticInternalMethod
MemberPrivateMethod
MemberProtectedMethod
MemberInternalMethod
get___StaticInternalProp
set___StaticInternalProp
get___StaticProtectedProp
set___StaticProtectedProp
get___MemberInternalProp
set___MemberInternalProp
get___MemberProtectedProp
set___MemberProtectedProp
__StaticProtectedMethod
__StaticInternalMethod
__MemberProtectedMethod
__MemberInternalMethod
Finalize
MemberwiseClone
InternalGetHashCode
obj_address
するとこのように親クラスの非Publicクラスメンバを取得することが出来ますが、取得できるのはProtectedまたはInternalのクラス関数のみでPrivateクラス関数は取得できません。
BindingFlags.FlattenHierarchy
は、親階層のPrivateクラスメンバ以外を検索の対象に加えます。
親クラスのPrivateクラスメンバは、サブクラスから親クラスを辿って取得する方法は無いようです。
最後に引数なしの場合の挙動
公式には以下のように説明しています。
指定した名前のパブリック フィールドを検索します。
GetMethodsの引数に何も指定しない場合は出力の通り、指定クラス及び親クラスのPublicメンバ
を取得できます。
検証コード
var methodInfos = typeof(SampleClass)
.GetMethods ();
foreach(var method in methodInfos) { Debug.Log (method.Name); }
出力
get_StatciPublicProp
set_StatciPublicProp
get_MemberPublicProp
set_MemberPublicProp
StaticPublicMethod
MemberPublicMethod
get___MemberPublicProp
set___MemberPublicProp
__MemberPublicMethod
Equals
GetHashCode
GetType
ToString
ちなみに、引数なしの状態をBindingFlagsで置き換えるとこうなります
var methodInfos = typeof(SampleClass)
.GetMethods (
BindingFlags.Instance |
BindingFlags.Static |
BindingFlags.Public
);
- BindingFlags.Instance
- BindingFlags.Static
- BindingFlags.Public
この3つを指定した状態と、引数を指定しない状態は一致します。
まとめ
BindingFlagsの種類は豊富ですが、関数を取得する場合は以下の5種類で事足りそうです。
- BindingFlags.Instance・・・・インスタンスメンバ検索
- BindingFlags.Static・・・・・クラスメンバ検索
- BindingFlags.Public・・・・・Publicメンバ検索
- BindingFlags.NoPublic・・・・Publicメンバ以外検索
- BindingFlags.DeclaredOnly・・・指定階層メンバ検索
- BindingFlags.FlattenHierarchy・・・親階層のPrivateクラスメンバ以外を検索
[object Object],で出来ないこと
- サブクラスのメンバ取得 可能だった こちらの記事参考
- 親クラスのPrivateクラスメンバ取得
GetMethodsは指定方法が複数パターンあるので検証し、まとめたことで個人的には安心できてよかったなと思いました。
※もう忘れない、忘れてもこの記事を読めば思い出せる
関数調査編でほぼほぼネタ的には終了していますが、次回はフィールド調査編を書く予定です。
この記事が気に入ったらフォローしよう
- Unity5.5.1f1