8
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

GameObject起動時に自動でNullチェックを行う

Last updated at Posted at 2016-03-30

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()でバリデーションをかけていますが、好きなタイミングに変えても良いでしょう。

8
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?