我如何滥用null运算符?该评估是否为“空"?正确吗? [英] How am I misusing the null-coalescing operator? Is this evaluating "null" correctly?

查看:120
本文介绍了我如何滥用null运算符?该评估是否为“空"?正确吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to use the null-coalescing operator in a C# script in Unity, my project Scripting Runtime is set to .NET 4.x so it should work correctly.

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

The problem is that even though the LEFT operand evaluates to null, it does not correctly return the RIGHT operand.

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

Here is an example statement that does NOT work when the left Operand returns null:

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

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

Here is the SAME exact statement, except it explicitly passes null to the null-coalescing operator (this works correctly when run)

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

这是一个简短的脚本,可以轻松地直接在Unity中测试问题.

Here is a short script to easily test the problem directly in 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)中的检查器中单击组件的右上角来运行测试功能

You can run the test function by clicking the top right corner of the Component in the Inspector in Unity (2018.3.12f1)

使用测试脚本时,第一次使用Null Coalescing运算符将失败,但是当我显式检查null,然后(通过三元运算符)冗余地传递null时,第二次使用会成功

When using the test script, the first use of the Null Coalescing operator will fail, but the second succeeds when I check for null explicitly, and then redundantly pass null (with the ternary operator)

Unity编辑器控制台中的输出:

Output in Unity Editor Console:

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

Is this a bug? or am I doing something wrong?

_______________________________

在寻找解决方法时,我发现了一种不错的方法,以使null运算符成为return REAL null:

In looking for a workaround I found a decent way to make return REAL null for the sake of the null-coalescing operator:

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

        if ( component == null )
            return null;

        return component;
    }

或者对于添加/获取组件的更具体的情况:

Or for more specific cases of adding/getting components:

    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;
    }

推荐答案

这是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对象.空合并运算符检查字面上的空.

Because Unity has overridden Equals (and the == operator) on all Unity objects so that destroyed game objects and never existing objects are both "equal" to null (this was done in an attempt to make developer's lives easier). But a destroyed (or "missing") object is not literally null: its a wrapper object in the C# part of the engine pointing at a null object in the underlying C++ code. The null coalescing operator checks for literally 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.

This is also why you get a MissingReferenceException when you try to access Unity objects that are null, rather than a NullReferenceException: those objects aren't literally null, but only effectively null.

这篇关于我如何滥用null运算符?该评估是否为“空"?正确吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆