繁体   English   中英

GetComponent 返回“null”而不是 null

[英]GetComponent returning "null" instead of null

如果请求的组件未附加到对象,我对GetComponent的返回值感到困惑。 根据 Unity 文档, GetComponent应该返回 null。 但是,似乎正在发生的是GetComponent返回请求类型的“null”对象,而不是值null

在此示例中,我的游戏对象没有附加CircleCollider2D 当我在CircleCollider2D x = GetComponent<CircleCollider2D>();行上设置断点时 我得到这个结果

为什么返回值不为null

编辑:

这是调试器中代码和值的完整屏幕截图。

另一个编辑:

是不是 Unity 重载了==运算符,以便GetComponent始终返回一个对象,但该对象可以具有内部“null”状态,与null相比返回 true ? 我可以在UnityEngine命名空间中看到以下声明

public static bool operator ==(Object x, Object y);
public static bool operator !=(Object x, Object y);

似乎GetComponent<T>()不返回TRUE null 相反,它返回带有默认值的新 T,在使用任何空字段时会触发MissingComponentException GetInstanceID()GetHashCode()之所以有效,是因为它们只使用设置为默认值 0 的int m_InstanceID 。不确定ToString()是如何工作的,但它可能在m_InstanceID == 0时返回"null"

证明:

void Start()
    {
        CircleCollider2D getComponent = GetComponent<CircleCollider2D>();
        CircleCollider2D empty = null;
        CircleCollider2D newCC = new CircleCollider2D();
        Debug.LogFormat("getComponent.GetInstanceID() {0}", getComponent.GetInstanceID());
        Debug.LogFormat("newCC.GetInstanceID() {0}", newCC.GetInstanceID());
        try
        {
            Debug.LogFormat("empty.GetInstanceID() {0}", empty.GetInstanceID());
        }
        catch (System.NullReferenceException e)
        {
            Debug.Log("empty.GetInstanceID() doesnt work, im true null");
        }
        try
        {
            string t = getComponent.name;
        }
        catch (System.Exception e)
        {
            Debug.Log(string.Format("getComponent fires {0} when any field is null", 
                e.ToString()));
        }
        try
        {
            string t = newCC.name;
        }
        catch (System.Exception e)
        {
            Debug.Log(string.Format("newCC fires {0} when any field is null",
                e.ToString()));
        }
    }

结果:

getComponent.GetInstanceID() 0
newCC.GetInstanceID() 0
empty.GetInstanceID() doesnt work, im true null
getComponent fires UnityEngine.MissingComponentException
newCC fires System.NullReferenceException

还:

getComponent.GetHashCode() = 0
getComponent.ToString() = "null"

为什么getComponent == null是真的? 通常它只是:

`getComponent.GetInstanceID() == otherComponent.GetInstanceID()`

o == null的情况下,它是:

return !(
o.GetCachedPtr() != IntPtr.Zero || (!(o is MonoBehaviour) && 
!(o is ScriptableObject) &&
Object.DoesObjectWithInstanceIDExist(o.GetInstanceID())));

所以我猜 InstanceID = 0 的对象永远不存在。 如果您想了解更多信息,请搜索反编译的 UnityEngine/UnityEngine/Object.cs。

会不会是 Unity 重载了 == 运算符

Tldr:的。

为什么返回值不为空?

根据自定义 == 运算符,我们应该保留它吗?

当 MonoBehaviour 有字段时,仅在编辑器中,我们不会将这些字段设置为“真正的空”,而是设置为“假空”对象。

为什么? 根据那篇文章,基本上有两个原因:

  • 在编辑器模式下:获取有关调用的更多上下文信息,因此如果您有异常,您将能够知道哪个对象是原因。

  • 来自UnityEngine.Object的所有内容都包装在 C# 对象中,以保留对 Unity C/C++ GameEngine 对象的引用。 在编辑器/代码中,我们使用 C# 元素,但这些只是对“真实”c++ 对象的引用。 现在,那些“真正的”c++ 对象的生命周期被显式处理(如果你destroy C++ 对象,它将被销毁,分配的内存将被释放)但是当垃圾收集器决定释放时,C# 对象将被完全销毁那个记忆。 因此,您将有一个指向空 C++ 对象的非空 C# 对象。 使用这个假的 null技巧,您将知道这个特定的 C# 对象为null ,因为在 C++ 端它被破坏了。


当你有一个单例并且if (sm_Instance == null)没有按预期工作时,这也很重要,你可以使用: if (EqualityComparer<T>.Default.Equals(sm_Instance, null)) instad。

编辑:如果您的单例使用泛型并且您的类型约束是class ,这可能会导致

public class Singleton<T> where T : class {

这将导致使用类对象的==运算符,即使您的单例是 GameEngine 对象。 一个解决方案? 您可以使用UnityEngine.Object而不是class ,例如:

public class Singleton<T> where T : UnityEngine.Object {

相关主题:
https://forum.unity3d.com/threads/null-check-inconsistency-c.220649/#post-1775701


ps:如果你去UnityEngine.Object组装,你就能看到重载:

UnityEngine.Object

快到最后了……

超载

如果您仍在寻找解决方案,这对我有用`

var component = parent.GetChild(i).GetComponent<T>();
if(component != null)
{
    if (component.ToString().Equals("null") == false)
    {
        list.Add(component);
    }
}

GetComponent应返回 'Component 类型的对象. Hence it is not expected to return "null" rather ~null . Hence it is not expected to return "null" rather ~null是预期值。 也许这种奇怪的行为应该报告给unity3d

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM