Проверьте, назначен ли GameObject в инспекторе в Unity3D 2019.3.05f.

Вопрос:

Как проверить, был ли назначен общедоступный игровой объект MonoBehaviour в инспекторе в Unity3D, поскольку сравнение для null (object==null) не выполняется.

Конкретный пример:

Я собираюсь написать общий метод для Unity3D, который можно вызывать для любого объекта, допускающего значение NULL. Он проверяет, является ли объект нулевым, и если да, то записывает Debug.LogError(customMessage). Метод выглядит следующим образом:

 public static bool IsNull<T>([CanBeNull] this T myObject, string message = "")
 {
     if (myObject!= null) return false;
     Debug.LogError("The object is null! " + message);
     return true;
 }

Этот метод можно вызывать для любого объекта, допускающего значение NULL, в любом месте кода, например, в этом простом моноповедении:

public class TestScript : MonoBehaviour
{
    public GameObject testObject = null;

    public void TestObject()
    {
        var result = testObject.IsNull("Error message");
        Debug.Log(result);
        Debug.Log(testObject);
    }
}

В большинстве случаев мой метод работает отлично и экономит много времени при кодировании/отладке. Но моя проблема сейчас в том, что если я не подписал "testObject" в редакторе, мой тест не будет работать, потому что testObject кажется не нулевым, но его также нельзя использовать, потому что он не назначен. В этом случае вывод консоли:

Ложь
null

Как получается, что (myObject == null) является ложным, а Debug.Log(testObject) дает мне null, пока соответствующий объект не был назначен в инспекторе единства.

Редактирование/решение. Благодаря помощи derHugo я получил этот общий фрагмент кода:

 public static bool IsNull<T>(this T myObject, string message = "") where T : class
    {
        switch (myObject)
        {
            case UnityEngine.Object obj when !obj:
                Debug.LogError("The object is null! " + message);
                return true;
            case null:
                Debug.LogError("The object is null! " + message);
                return true;
            default:
                return false;
        }
    }

person DaveM    schedule 12.02.2020    source источник


Ответы (1)


В Unity есть собственная реализация оператора равенства == (см. Пользовательский оператор ==, следует ли его сохранить? что часто приводит к путанице/неожиданному поведению.

Даже если UnityEngine.Object имеет значение, равное null, иногда оно не равно == null. Object все еще хранит в нем некоторые метаданные, например. вы получаете MissingReferenceException, а не обычное NullReferenceException, потому что Unity реализовала некоторые пользовательские исключения, которые часто содержат более подробную информацию о том, почему значение равно null.

Особенно с

public GameObject testObject = null;

является полем public, оно автоматически сериализуется, поэтому присвоенное ему значение null в любом случае будет перезаписано во время сериализации.


UnityEngine.Object, производным от которого является GameObject, имеет неявный оператор bool

Объект существует?

Вместо прямого == null сравнения лучше проверить

public static bool IsNull<T>(this T myObject, string message = "") where T : UnityEngine.Object
{
    if(!myObject)
    {
        Debug.LogError("The object is null! " + message);
        return false;
    }

    return true;
}

Для общего метода, работающего для любого ссылочного типа, вы можете, например. использовать что-то вроде

public static bool IsNull<T>(this T myObject, string message = "") where T : class
{
    if (myObject is UnityEngine.Object obj)
    {
        if (!obj)
        {
            Debug.LogError("The object is null! " + message);
            return false;
        }
    }
    else
    {
        if (myObject == null)
        {
            Debug.LogError("The object is null! " + message);
            return false;
        }
    }

    return true;
}
person derHugo    schedule 12.02.2020
comment
Спасибо, это очень хорошо. Благодарю вас. Есть ли способ перегрузить этот метод таким образом, чтобы он также применялся ко всем объектам Not Unity Engine, чтобы я мог затем классическим способом проверить все другие значения NULL на значение NULL? - person DaveM; 12.02.2020