Как я неправильно использую оператор слияния?Правильно ли оценивается «ноль»? - PullRequest
3 голосов
/ 03 июля 2019

Я пытаюсь использовать оператор объединения нулей в сценарии C # в Unity, мой проект Scripting Runtime установлен на .NET 4.x, поэтому он должен работать правильно.

Проблема в том, что даже еслиоперанд LEFT оценивается как ноль, он неправильно возвращает правый операнд.

Вот пример оператора, который НЕ работает , когда левый операнд возвращает ноль:

m_meshFilter = ( GetMeshFilter() ?? AddMeshFilter() );

Вот то же самое точное утверждение, за исключением того, что оно явно передает ноль оператору объединения нулей (, это работает правильно при запуске )

m_meshFilter = ( GetMeshFilter() == null ? null : GetMeshFilter() ) ?? AddMeshFilter();

Вот короткий скрипт, который легкопротестируйте проблему непосредственно в Unity.

using UnityEngine;

public class DoubleQuestionTest : MonoBehaviour
{
    public GameObject myGo;

    public MeshFilter m_meshFilter = null;

    [ContextMenu( "Test1 Null Coalescing Operator" )]
    void Test1()
    {
        m_meshFilter = ( GetMeshFilter() ?? AddMeshFilter() );

        if ( m_meshFilter == null )
        {
            Debug.Log( "m_meshFilter was null, trying Alternate" );
            m_meshFilter = ( GetMeshFilter() == null ? null : GetMeshFilter() ) ?? AddMeshFilter();
        }
    }

    MeshFilter GetMeshFilter()
    {
        MeshFilter temp = myGo.GetComponent<MeshFilter>();

        if ( temp == null )
            Debug.Log( "    > Get Mesh Filter RETURNING NULL" );

        return temp;
    }

    MeshFilter AddMeshFilter()
    {
        Debug.Log( "    > Add Mesh Filter Called" );
        return myGo.AddComponent<MeshFilter>();
    }
}

Функцию тестирования можно запустить, щелкнув верхний правый угол компонента в Инспекторе в Unity (2018.3.12f1)

При использованииВ тестовом сценарии первое использование оператора Null Coalescing завершится неудачно, но второе выполнится успешно, когда я явно проверю на null, а затем с избыточностью передам null (с троичным оператором)

Вывод в консоли редактора Unity:

Image Output!

Это ошибка?или я что-то не так делаю?

_______________________________

РЕДАКТИРОВАТЬ:

В поисках обходного пути я нашел приличный способсделать возврат REAL null ради оператора слияния нуль:

    public static T GetComponentRealNull<T>( this GameObject self ) where T : Component
    {
        T component = self.GetComponent<T>();

        if ( component == null )
            return null;

        return component;
    }

или для более конкретных случаев добавления / получения компонентов:

    public static T GetComponentOrAddIfMissing<T>(this GameObject self) where T : Component
    {
        T component = self.GetComponent<T>();
        if(component == null)
            component = self.AddComponent<T>();

        return component;
    }

1 Ответ

6 голосов
/ 03 июля 2019

Это Unity завладевает вами.

Если вы сделаете это:

MeshFilter GetMeshFilter()
{
    MeshFilter temp = myGo.GetComponent<MeshFilter>();

    if ( temp == null ) {
        Debug.Log( "    > Get Mesh Filter RETURNING NULL" );
        return null;
    }
    return temp;
}

Это работает.

Почему?

Потому что Unity имеетпереопределить Equals (и оператор ==) на всех объектах Unity, так что уничтоженные игровые объекты и никогда не существующие объекты оба "равны" нулю (это было сделано впопытка сделать жизнь разработчика проще).Но уничтоженный (или «отсутствующий») объект не является буквально null: это объект-оболочка в части C # движка, указывающий на нулевой объект в базовом коде C ++.Нулевой оператор объединения объединяет буквально ноль.

Например, попробуйте это:

Start() {
    GameObject gg = new GameObject(); //create a GO
    DestroyImmediate(gg); //destroy it immediately
    Debug.Log(gg == null); //prints true: it is definitely null!
    GameObject go = gg ?? this.gameObject; //get a non-null object
    Debug.Log(go); //prints null
}

По этой же причине вы получаете MissingReferenceException при попытке получить доступ к объектам Unity.имеют значение null, а не NullReferenceException: эти объекты не буквально null, а только эффективно null.

...