こんにちは、Unityエンジニアのオオバです。

UnityというかC#の話です。
Unityの隠蔽関数を調べたい時がよくあります。

そんな時リフレクションを使って関数や変数を調べることが多いと思います。
リフレクション使用時にBindingFlagsを使うわけですが結構種類があり、どれを使ってよいのか忘れてしまうので整理しておこうと思います。

公式リファレンスはこちら BindingFlags 列挙型 (System.Reflection) | Microsoft Docs

※本記事はタイトルの通り関数リフレクションに絞った記事です

👉DOTweenの教科書を読んでUnityアニメーションをプログラミングしてみよう!

リフレクションを使って関数列挙する

GetMethods.cs · GitHub

簡単に説明すると、Type型に対しGetMethods関数 を実行して関数情報を保持したデータMethodInfoの配列を取得できます。
GetMethods関数の引数 に先のBindingFlagsを指定することで取得する関数を調整することが出来ます。


ここからは、確認用として以下のサンプルクラスを使って検証します。

SampleClass.cs · GitHub

指定クラス階層のPublicメンバを取得

親クラス

検証コード

var methodInfos = typeof(SampleClass)  
    .GetMethods (  
        BindingFlags.Instance |  
        BindingFlags.Static |  
        BindingFlags.Public |  
        BindingFlags.DeclaredOnly  
    );  
foreach(var method in methodInfos) { Debug.Log (method.Name); }  

この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.PublicBindingFlags.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  
    );  

この3つを指定した状態と、引数を指定しない状態は一致します。

まとめ

BindingFlagsの種類は豊富ですが、関数を取得する場合は以下の5種類で事足りそうです。

[object Object],で出来ないこと

GetMethodsは指定方法が複数パターンあるので検証し、まとめたことで個人的には安心できてよかったなと思いました。
※もう忘れない、忘れてもこの記事を読めば思い出せる

関数調査編でほぼほぼネタ的には終了していますが、次回はフィールド調査編を書く予定です。

オススメ記事
検証環境