【问题标题】:Why do if statements in Unity3d C# allow objects that are not bools?为什么 Unity3d C# 中的 if 语句允许非布尔对象?
【发布时间】:2021-12-09 14:46:32
【问题描述】:

在标准 .NET 4.6 编译器中,以下 if 语句不合法,您将得到编译器错误:CS0029 无法将类型 'UserQuery.TestClass' 隐式转换为 'bool'。这一切都很好,我理解这一点。

void Main()
{
    TestClass foo = new TestClass();

    if(foo) 
    {
        "Huh. Who knew?".Dump();
    }
}


public class TestClass : Object
{
}

然而,在 Unity3d 中,这段代码是完全合法的,我见过几个例子,甚至鼓励这种 Javascript 风格的 null 检查。

这里发生了什么,是否可以在我在 .NET 中的非 Unity3d 工作中利用这一点?

这里是 Unity3D 中的合法代码示例:

using UnityEngine;

public class SampleIfBehavior : MonoBehaviour
{

    // Use this for initialization
    void Start ()
    {
        var obj = new SampleIfBehavior();

        if (obj)
        {
            Console.Write("It wasn't null.");
        }
    }
}

剧情变厚了!如果我尝试比较一个不是从单声道行为派生的对象,我会收到预期的编译器警告。

public class TestClass
{
}
void Start ()
{
    var obj2 = new TestClass();
    if (obj2) // cast from TestClass to bool compiler error
    {

    }
}

感谢 Programmer,我一直挖掘到 Unity3D 的 Object(我忽略了它,因为我错误地认为它是 .NET 的实际对象。)

好奇的相关代码(在UnityEngine.Object中):

public static implicit operator bool(Object exists)
{
  return !Object.CompareBaseObjects(exists, (Object) null);
}

public static bool operator ==(Object x, Object y)
{
  return Object.CompareBaseObjects(x, y);
}

public static bool operator !=(Object x, Object y)
{
  return !Object.CompareBaseObjects(x, y);
}

【问题讨论】:

  • @GrantWinney 添加了可工作的 unity3d 代码。
  • 谈到您编辑的问题,大多数人认为 Unity 使用 .NET 对象。它使用UnityEngine.Object,如果你不注意,这可能会混淆。

标签: c# unity3d


【解决方案1】:

不要太担心这个。 if (obj) 仅在 Unity 中是合法的,因为在 Unity 中存在隐式运算符重载。它在UnityEngine.Object 类中完成。

看起来像这样:

  public static implicit operator bool(Object obj)
     {
       return (obj != null);
     }

Unity 计划删除此功能,但决定反对它,因为它会破坏所有 Unity 代码。你可以阅读更多关于这个here的信息。

此功能的非常糟糕的一面是它无法在编辑器中使用 Null-Coalescing 运算符功能。 好的一面是它简化了对 null 的检查。

【讨论】:

  • 这如何导致无法在编辑器中使用 Null-Coalescing 运算符功能?
【解决方案2】:

我阅读了很多关于这个主题的文章,包括 @Programmerother on stackoverflow 提到的。可能问题的根源很清楚,特别是在删除 GameObject(通过示例)以及在使用 "!=null" or "!((bool)GameObject)" 对其存在进行测试之后。 我决定对该问题进行简单检查(Unity 2019.4.14 LTS): 一个将被删除的 GameObject 有脚本

    public class CheckDestroy : MonoBehaviour
    {
        public OnGUITest linkToMangerObject;
    
        private void OnMouseDown()
        {
            linkToMangerObject.InitCount();
            Destroy(gameObject);
        }
    }

其他游戏对象,测试是否存在已删除对象:

   public class OnGUITest : MonoBehaviour
   {
        private int externalCount;
        private bool flagObjectDeleted = false;
        public GameObject deletedObject;
    
        void OnGUI()
        {
           if (flagObjectDeleted)
                if  (deletedObject)
                //if (deletedObject != null)
                    externalCount++;
                else
                    print($"Detected the object deleted, count={externalCount}");
        }
    
        public void InitCount()
        {
            externalCount = 0;
            flagObjectDeleted = true;
        }
    }

结果是验证对象立即检测到其他对象的销毁。 这是一个综合测试,具有最大的简单场景和最小的 CPU/Mem 和垃圾收集负载。

也许在实际情况下(在实际负载下)它会以不同的方式工作,或者可能是本机代码已更改 - 添加了额外的检查?

【讨论】:

    猜你喜欢
    • 2022-01-10
    • 1970-01-01
    • 2015-11-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-26
    • 2019-10-04
    • 2013-03-01
    • 1970-01-01
    相关资源
    最近更新 更多