簡體   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