fc2ブログ
ヽ|∵|ゝ(Fantom) の 開発blog? ホーム » Unity »【Unity】【C#】インスペクタでの UnityEvent のコールバック登録の有無を調べる

【Unity】【C#】インスペクタでの UnityEvent のコールバック登録の有無を調べる  


 利用頻度はあまり高くはないかもだが、インスペクタでの UnityEvent のコールバック登録があるか否かを調べたいときがある。実際に利用するには調べたい条件によってコードを変えるしかないかも知れないが、簡単な例を2つばかり挙げておこう。また、UnityEvent にはジェネリックパラメタの数違いのパターンがあるので、それらをカバーするためのオーバーロードも簡単に作っておく。

 ここでは汎用的に使えるように、拡張メソッドとして定義したものを書いておこう。ライブラリとして保存しておけば使い回しもできると思う。拡張メソッドにしたくない場合は、メソッドの引数の this を取り除けば良い。


(※) Unity 5.6.3p1 - 2018.1.8f1 / Windows10(x64) で確認



■インスペクタの UnityEvent にコールバックが1つでも登録されてるか否かを返す

 このメソッドたちは1つでもコールバック名が有るか無いかという判別をするものである。UnityEvent が null のときは常に false になる。ジェネリックパラメタの数違いはオーバーロードとして定義している。

●インスペクタの UnityEvent にコールバックメソッドが存在するか否かを返す(関数定義)
using System;
using UnityEngine;
using UnityEngine.Events;

public static class Extensions //※クラス名は任意
{
//インスペクタの UnityEvent にコールバックが1つでも登録されてるか否かを返す。
//※AddListener() で登録したものは無視されるので注意。
public static bool HasRegistered(this UnityEventBase obj)
{
if (obj != null)
{
int count = obj.GetPersistentEventCount(); //※AddListener() には無効
for (int i = 0; i < count; i++)
{
if (!string.IsNullOrEmpty(obj.GetPersistentMethodName(i))) //※AddListener() には無効
return true;
}
}
return false;
}

//※以下、パラメタ違いオーバーロード
public static bool HasRegistered(this UnityEvent obj)
{
return HasRegistered((UnityEventBase)obj);
}

public static bool HasRegistered<T0>(this UnityEvent<T0> obj)
{
return HasRegistered((UnityEventBase)obj);
}

public static bool HasRegistered<T0, T1>(this UnityEvent<T0, T1> obj)
{
return HasRegistered((UnityEventBase)obj);
}

public static bool HasRegistered<T0, T1, T2>(this UnityEvent<T0, T1, T2> obj)
{
return HasRegistered((UnityEventBase)obj);
}

public static bool HasRegistered<T0, T1, T2, T3>(this UnityEvent<T0, T1, T2, T3> obj)
{
return HasRegistered((UnityEventBase)obj);
}
}

●使用例(メインでのコードなど)
using UnityEngine;

Debug.Log("OnNothing.HasRegistered = " + OnNothing.HasRegistered());
Debug.Log("OnSingle.HasRegistered = " + OnSingle.HasRegistered());
Debug.Log("OnDouble.HasRegistered = " + OnDouble.HasRegistered());
Debug.Log("OnTriple.HasRegistered = " + OnTriple.HasRegistered());
Debug.Log("OnQuadruple.HasRegistered = " + OnQuadruple.HasRegistered());


//コールバックハンドラなど
public void ReceiveNothing()
{
Debug.Log("ReceiveNothing called.");
}

public void ReceiveSingle(string s)
{
Debug.Log("ReceiveSingle called.");
}

public void ReceiveDouble(string s, int i)
{
Debug.Log("ReceiveDouble called.");
}

public void ReceiveTriple(string s, int i, float f)
{
Debug.Log("ReceiveTriple called.");
}

public void ReceiveQuadruple(string s, int i, float f, bool b)
{
Debug.Log("ReceiveQuadruple called.");
}

● False になる例

OnNothing.HasRegistered = False
OnSingle.HasRegistered = False
OnDouble.HasRegistered = False
OnTriple.HasRegistered = False
OnQuadruple.HasRegistered = False

● True になる例

OnNothing.HasRegistered = True
OnSingle.HasRegistered = True
OnDouble.HasRegistered = True
OnTriple.HasRegistered = True
OnQuadruple.HasRegistered = True

 注意して欲しいのは「GetPersistentEventCount()」や「GetPersistentMethodName()」というメソッドを使っているが、これらは「AddListener()」でランタイム時に追加したメソッドには無効ということだ。なので、基本的にはインスペクタでの登録のみと考えて欲しい(タイトルが「インスペクタでの~」となってるのはそのため)。

 また、メソッドの存在は「GetPersistentMethodName()」で空か否かで判断しているだけなので、何らかミスなどで "<Missing ~>"(※ここではわざと無効な Dummy() メソッドを登録している)となっているメソッドも存在していると判断されてしまうので注意しよう。しかし通常、インスペクタでの登録は正常であるという前提なら問題はない。



■インスペクタの UnityEvent にシグニチャが合致しているコールバックが1つでも登録されてるか否かを返す

 次のメソッドたちは前述のコールバック名の存在有無より厳密に、コールバックの引数のシグニチャと同じものだけを検出するものである。実際インスペクタでの登録は違うシグニチャも登録できるわけで(例:コールバック引数が(string s, int i)であっても、引数が(string s)[※インスペクタで文字列を入力] のメソッドを登録することができる)、便利ではあるが前述の方法では正しくコールバックできるメソッドが存在するかは判定できないことにもなる。以下の方法では完全に正しいシグニチャを持つメソッドしか検出しないので、"<Missing ~>"(※ここではわざと無効な Dummy() メソッドを登録している)となっているものも排除できる。

●インスペクタの UnityEvent に引数が正しいコールバックメソッドが存在するか否かを返す(関数定義)
using System;
using System.Reflection;
using UnityEngine;
using UnityEngine.Events;

public static class Extensions //※クラス名は任意
{
//インスペクタの UnityEvent にシグニチャが合致しているコールバックが1つでも登録されてるか否かを返す。
public static bool HasValidMethod(this UnityEventBase obj, Type[] argumentTypes)
{
if (obj != null)
{
int count = obj.GetPersistentEventCount(); //※AddListener() には無効
for (int i = 0; i < count; i++)
{
string method = obj.GetPersistentMethodName(i); //※AddListener() には無効
if (!string.IsNullOrEmpty(method))
{
object target = obj.GetPersistentTarget(i); //※AddListener() には無効
MethodInfo info = UnityEventBase.GetValidMethodInfo(target, method, argumentTypes);
if (info != null)
return true;
}
}
}
return false;
}

//※以下、パラメタ違いオーバーロード
public static bool HasValidMethod(this UnityEvent obj)
{
return HasValidMethod(obj, new Type[]{});
}

public static bool HasValidMethod<T0>(this UnityEvent<T0> obj)
{
return HasValidMethod(obj, new Type[]{typeof(T0)});
}

public static bool HasValidMethod<T0, T1>(this UnityEvent<T0, T1> obj)
{
return HasValidMethod(obj, new Type[]{typeof(T0), typeof(T1)});
}

public static bool HasValidMethod<T0, T1, T2>(this UnityEvent<T0, T1, T2> obj)
{
return HasValidMethod(obj, new Type[]{typeof(T0), typeof(T1), typeof(T2)});
}

public static bool HasValidMethod<T0, T1, T2, T3>(this UnityEvent<T0, T1, T2, T3> obj)
{
return HasValidMethod(obj, new Type[]{typeof(T0), typeof(T1), typeof(T2), typeof(T3)});
}
}

●使用例(メインでのコードなど)
using UnityEngine;

Debug.Log("OnNothing.HasValidMethod = " + OnNothing.HasValidMethod());
Debug.Log("OnSingle.HasValidMethod = " + OnSingle.HasValidMethod());
Debug.Log("OnDouble.HasValidMethod = " + OnDouble.HasValidMethod());
Debug.Log("OnTriple.HasValidMethod = " + OnTriple.HasValidMethod());
Debug.Log("OnQuadruple.HasValidMethod = " + OnQuadruple.HasValidMethod());

//・・・コールバックハンドラなどは前述と同じで良いので省略・・・

● False になる例

OnNothing.HasValidMethod = False
OnSingle.HasValidMethod = False
OnDouble.HasValidMethod = False
OnTriple.HasValidMethod = False
OnQuadruple.HasValidMethod = False

● True になる例

OnNothing.HasValidMethod = True
OnSingle.HasValidMethod = True
OnDouble.HasValidMethod = True
OnTriple.HasValidMethod = True
OnQuadruple.HasValidMethod = True

 使い分けは大まかに「何でも良いからメソッドが登録されてる」ときと「正確に値を返せるメソッドが登録されてる」となるだろう。どちらを使うかはケースバイケースだと思う。


(関連記事)
【Unity】【C#】UnityEvent, Action, delegate, interface でのコールバック実装方法とインスペクタでの登録
【Unity】【C#】長押し(ロングタップ)を取得してコールバックする
【Unity】【C#】スワイプ(フリック)を判定、方向を取得してコールバックする
【Unity】【C#】ピンチ操作を取得してコールバックする
【Unity】【C#】VideoPlayer で動画の終了判定をする


関連記事
スポンサーサイト



category: Unity

thread: ゲーム開発

janre: コンピュータ

tag: Unityライブラリ  Unityリファレンス  エディタ拡張  インスペクタ 
tb: 0   cm: --


トラックバック

トラックバックURL
→http://fantom1x.blog130.fc2.com/tb.php/305-f82ffe85
この記事にトラックバックする(FC2ブログユーザー)

プロフィール

Social

検索フォーム

全記事一覧

カテゴリ

ユーザータグ

最新記事

リンク

PR

▲ Pagetop