はじめに
プログラムを作っている際によく使いますよね、コールバック関数。
そこで毎回思うのが「Nullチェックのif文書くのがめんどくさい」
今回はNullチェックをしつつ、簡単に記述できる方法を考えてみようと思います。
環境
- Unity 2021.1.5f1
問題点
もし以下のようなプログラムだった場合
void Start()
{
TestCallback();
}
public void TestCallback(System.Action callback = null)
{
callback();
}
// この書き方でも一緒.
public void TestCallback(UnityEngine.Events.UnityAction callback = null)
{
callback();
}
callbackがnullだった場合に以下の様な例外(Exception)が発生してしまいます。
NullReferenceException: Object reference not set to an instance of an object
SampleSceneController.TestCallback (System.Action callback) (at Assets/Scenes/SampleSceneController.cs:23)
もしこのサンプルのようにコールバックを使う場合、以下のようにNullチェックをいれます。
public void TestCallback(System.Action callback = null)
{
if (callback != null)
{
callback();
}
}
こうすると、コールバックを設定していなかった場合でも例外を吐かなくなります。
ただ、コールバックを頻繁に使う場合に「このif文を毎回書くのがめんどくさい」です。
そこで色々なパターンを考えてみます。
Nullチェック付きでコールバックを呼ぶサンプル
if文を使う
まずは上記でも紹介したif文でチェックするパターンです。コールバックを頻繁に使わないのならばこれで十分かもしれません。
public void TestCallback(System.Action callback = null)
{
if (callback != null)
{
callback();
}
}
拡張クラスを用意する
拡張クラスを用意し、その中でNullチェックをしてコールバックを呼び出します。
public void TestCallback(System.Action callback = null)
{
callback.SafeCall();
}
System.Actionの拡張クラス
public static class ActionExtension
{
public static void SafeCall(this System.Action action)
{
if (action != null)
{
action();
}
}
public static void SafeCall<T>(this System.Action<T> action, T arg)
{
if (action != null)
{
action(arg);
}
}
public static void SafeCall<T1, T2>(this System.Action<T1, T2> action, T1 arg1, T2 arg2)
{
if (action != null)
{
action(arg1, arg2);
}
}
public static void SafeCall<T1, T2, T3>(this System.Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3)
{
if (action != null)
{
action(arg1, arg2, arg3);
}
}
}
UnityEngine.Events.UnityActionの拡張クラス
public static class UnityActionExtension
{
public static void SafeCall(this UnityEngine.Events.UnityAction action)
{
if (action != null)
{
action();
}
}
public static void SafeCall<T>(this UnityEngine.Events.UnityAction<T> action, T arg)
{
if (action != null)
{
action(arg);
}
}
public static void SafeCall<T1, T2>(this UnityEngine.Events.UnityAction<T1, T2> action, T1 arg1, T2 arg2)
{
if (action != null)
{
action(arg1, arg2);
}
}
public static void SafeCall<T1, T2, T3>(this UnityEngine.Events.UnityAction<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3)
{
if (action != null)
{
action(arg1, arg2, arg3);
}
}
}
Nullチェックする外部メソッドを作成する
Nullチェックをしてからメソッド呼び出す外部メソッドを作成するパターン
public void TestCallback(System.Action callback = null)
{
SystemUtility.SafeCall(callback);
}
外部メソッド例
public static class SystemUtility
{
public static void SafeCall(System.Action action)
{
if (action != null)
{
action();
}
}
}
これ、作るくらいなら拡張クラスのほうがわかりやすい気がします。
null 条件演算子を使ってからInvokeで呼ぶ
これが自分的には一番おすすめで、簡潔な気がします。
public void TestCallback(System.Action callback = null)
{
callback?.Invoke();
}
この書き方だと拡張クラス等なにも準備しなくてすむので、一番ラクですね。
さいごに
一番のおすすめは「null条件演算子を使ってからInvokeで呼ぶ」パターンですが、古いUnityだとC#のバージョンの制限により使うことができません。
その場合は、拡張クラスを使う方法が良いと思います。
コメント
Hello.
Hello.
Hello.
Hello from Happykiddi.