为什么Unity3d C#中的if语句允许不是bool的对象?

时间:2017-08-08 00:37:06

标签: c# unity3d

在标准.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风格的空检查。

这里发生了什么,是否可以在.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);
}

2 个答案:

答案 0 :(得分:11)

不要过分担心这一点。 if (obj)仅在Unity中合法,因为Unity中存在隐式运算符重载。我相信这是在MonoBehaviourUnityEngine.Object类中完成的。

它看起来像这样:

public static implicit operator bool($classname$ other){
    return other != null;
}

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

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

答案 1 :(得分:0)

我阅读了许多有关此主题的文章,其中包括 @Programmer other 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);
        }
    }

其他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和垃圾回收的负载最小。

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

enter image description here