我如何滥用null运算符?这是否正确评估为“ null”?

时间:2019-07-03 18:01:12

标签: c# unity3d null-coalescing-operator

我试图在Unity中的C#脚本中使用null-coalescing运算符,我的项目Scripting Runtime设置为.NET 4.x,因此它应该可以正常工作。

问题在于,即使LEFT操作数计算为null,也无法正确返回RIGHT操作数。

这是一个示例语句,当左操作数返回null时,不起作用

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

这里是SAME确切的语句,除了它显式地将null传递给null-coalescing运算符(运行时正确运行

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

这是一个错误吗?还是我做错了什么?

_______________________________

编辑:

在寻找解决方法时,我找到了一种不错的方法,以使null运算符成为return 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 个答案:

答案 0 :(得分:6)

这是Unity与您为伍。

如果您这样做:

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

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

有效。

为什么?

因为Unity在所有Unity对象上都覆盖了Equals(和==运算符),所以被破坏的游戏对象和从不存在的对象两者都等于等于null(这样做是为了使开发人员的生活更轻松)。但是,被破坏(或“丢失”)的对象不是 literally null:它是引擎C#部分中的包装对象,指向基础C ++代码中的null对象。空合并运算符检查字面上的空。

例如,尝试以下操作:

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
}

这也是为什么当您尝试访问为null而不是NullReferenceException的Unity对象时会得到MissingReferenceException的原因:这些对象不是 literally null,而是有效的 null。

相关问题