読者です 読者をやめる 読者になる 読者になる

渋谷ほととぎす通信

完全趣味でやってるUnityメモ。説明できないところを説明できるようにするための個人ブログ。昨日の自分より少しでも大きく慣れるように。。。 ※所属団体とは一切関係がありません

BindingFlagsは一旦これだけ覚えておこう


f:id:esakun:20170206021040p:plain

環境

  • Unity5.5.1f1

Unityの隠蔽関数を調べたい時がよくあります。

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

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

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

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

簡単に説明すると、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.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
    );
  • BindingFlags.Instance
  • BindingFlags.Static
  • BindingFlags.Public

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

まとめ

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

  • BindingFlags.Instance・・・・インスタンスメンバ検索
  • BindingFlags.Static・・・・・クラスメンバ検索
  • BindingFlags.Public・・・・・Publicメンバ検索
  • BindingFlags.NoPublic・・・・Publicメンバ以外検索
  • BindingFlags.DeclaredOnly・・・指定階層メンバ検索
  • BindingFlags.FlattenHierarchy・・・親階層のPrivateクラスメンバ以外を検索

GetMethods関数で出来ないこと

  • サブクラスのメンバ取得
  • 親クラスのPrivateクラスメンバ取得

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

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

プログラミングC# 第7版 改訂3版 パーフェクトC# (PERFECT SERIES 1) 独習C# 第3版

合わせてどうぞ

www.shibuya24.info

www.shibuya24.info

www.shibuya24.info

www.shibuya24.info

www.shibuya24.info