为何泛型类中Unity Object空值与null不等,特化类中却相等?
问题:为何泛型类中的Unity Object空值与null不相等?
将TestMono挂载至空GameObject,留空序列化字段uov后运行,结果与预期不符。
相关代码
泛型与特化类定义
using System; using UnityEngine; using Object = UnityEngine.Object; namespace TestMisc.Scripts { [Serializable] public class Variable<T> { [SerializeField] T m_Value; public T Value => m_Value; public void LogInsideGenericClass() { // Result: Inside generic class: equal to null: False equal to default: True Debug.Log($"Inside generic class: equal to null: {Value == null} equal to default: {Value as Object == default}"); } } [Serializable] public class UnityObjectVariable : Variable<Object> { public void LogInsideSpecializedClass() { // Result: Inside specialized class: equal to null: True equal to default: True Debug.Log($"Inside specialized class: equal to null: {Value == null} equal to default: {Value as Object == default}"); } } }
测试脚本
using UnityEngine; namespace TestMisc.Scripts { public class TestMono : MonoBehaviour { [SerializeField] UnityObjectVariable uov; void Start() { uov.LogInsideGenericClass(); uov.LogInsideSpecializedClass(); } } }
原因解析
这本质是Unity自定义对象系统和C#泛型运算符解析逻辑的冲突:
UnityEngine.Object重载了==运算符,它不仅检查引用是否为真null,还会判断对象背后的Native资源是否有效——比如序列化未赋值、对象被Destroy的情况,Unity会把这类对象标记为“假null”(实际是持有无效资源的UnityEngine.Object实例)。- 在泛型类
Variable<T>中,Value == null的逻辑是编译时确定的:因为T是泛型参数,编译器无法提前预知它会被特化为UnityEngine.Object,所以会使用C#默认的引用相等检查——只判断引用是不是真的null。而序列化未赋值的m_Value是一个“假null”实例(不是真null),所以Value == null返回False。 - 在特化类
UnityObjectVariable中,Value的类型明确是UnityEngine.Object,此时== null会直接调用Unity重载的运算符,能正确识别出“假null”,所以返回True。 - 至于
Value as Object == default能返回True,是因为as运算符遇到Unity的假null时会返回真null,自然和default(Object)(即null)相等。
内容的提问来源于stack exchange,提问作者Hailin Li
相关产品推荐
相关产品推荐

