nullポで動きません?
SerializeField属性を使いinspectorで参照を入れるプロパティは、nullでない前提で制作を行う事が多いと思います。
しかし、変数名のリネームなどで、うっかりnullになっている事がしばしばあります。
自動でバリデーションをかける
もしそういった事があっても、すぐに気づけるようにStart()のタイミングで自動でnullチェックをするというアイディアのサンプルです。
nullを許容したい場合もあるかと思いますので、SerializeFieldを全部チェックではなく、あらたなAttributeを定義し、それでマークされた変数をチェックする事にします。
using System;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Assertions;
using System.Reflection;
using System.Diagnostics;
class NullCheckMonoBehaviour : MonoBehaviour
{
// カスタムAttribute [NotNull] の定義
[AttributeUsage(
AttributeTargets.All,
AllowMultiple = true,
Inherited = false)]
public class NotNull : Attribute {}
[SerializeField, NotNull]
GameObject go;
[SerializeField, NotNull]
GameObject go2;
[SerializeField, NotNull]
public Transform tr;
[SerializeField, NotNull]
protected Button btn;
// 独自クラスでのテスト用
class Something
{
}
[NotNull]
Something some;
void Start ()
{
CheckNull();
}
[Conditional("DEBUG")]
void CheckNull()
{
foreach (FieldInfo fieldInfo in GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
{
if (fieldInfo.GetCustomAttributes(typeof(NotNull), false).Length > 0)
{
object field = fieldInfo.GetValue(this);
// Assert使うならこちら
// Assert.AreNotEqual(null, field, string.Format("{0} : [{1}] is null", gameObject.name, fieldInfo.Name));
if (field == null || field.Equals(null))
{
string log = string.Format("{0} : [{1}] is null", gameObject.name, fieldInfo.Name);
UnityEngine.Debug.LogError(log);
}
}
}
}
}
上記コードをコピペしたクラスをgameObjectにアタッチし、インスペクターから変数をいれたり、わざとNoneにしたりして試して下さい。
解説
・独自の属性の定義
冒頭で、カスタム属性のNotNullを独自に定義しています。(NotNullというクラス名は適当です (^_^;))
・開発環境でのみ実行
Conditional属性で制御しています。
・リフレクション
リフレクションを使ってNotNullが設定された変数を取得しています。
・field.Equalsでnullチェック
if (field == null || field.Equals(null))
field.Equalsも使用しているのは、UnityEngine.Objectを継承している変数が field == null でtrueを返さないためです。
あまり深く調査していませんが、UnityEngine.Objectが独自に == を実装しているためと思われます。
(object.ReferenceEquals(someObject, null) の方が someObject == null より早い…が、盲目的に使うのは危険を参照)
・タイミング
Start()でバリデーションをかけていますが、好きなタイミングに変えても良いでしょう。