[英]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组装,你就能看到重载:
快到最后了……
如果您仍在寻找解决方案,这对我有用`
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.