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

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

问题描述

我试图在 Unity 的 C# 脚本中使用空合并运算符,我的项目脚本运行时设置为 .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.

问题是,即使左操作数的计算结果为空,它也没有正确返回右操作数.

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() );

这是相同的精确语句,除了它显式地将 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)中点击Inspector中Component右上角即可运行测试功能

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?

_______________________________

在寻找解决方法时,我找到了一种体面的方法,为了空合并运算符而返回 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(这样做是为了让开发人员的生活更轻松).但是被破坏(或丢失")的对象不是字面空:它是引擎的 C# 部分中的一个包装对象,指向底层 C++ 代码中的空对象.空合并运算符检查字面上的空值.

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 的 Unity 对象时会得到 MissingReferenceException 而不是 NullReferenceException 的原因:这些对象不是字面上 null,而只是有效em> 空.

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.

通常,Object.bool 运算符 用于.只是更喜欢使用它而不是 null 检查:

In general that's what the Object.bool operator is used for. Just prefer to use it instead of a null check:

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

    if(!component) component = self.AddComponent<T>();

    return component;
}

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

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