Unity中为何null变量同时满足==null与is BoxExit判断?
核心原因:Unity对MonoBehaviour子类重写了==运算符
你遇到的问题本质是Unity的"假Null"机制:对于继承自MonoBehaviour的类(比如你的BoxExit),Unity重写了==运算符和null判定逻辑。当一个MonoBehaviour对象被Destroy()销毁、或者其所在GameObject被禁用/销毁时,Unity会让== null返回true,但这个对象在CLR(公共语言运行时)层面并没有真正变为null——它仍然保留着完整的类型信息,只是被Unity标记为"无效对象"。
所以你的代码里:
mirr == null:Unity判定这个BoxExit实例已无效,返回truemirr is BoxExit:CLR检查对象的实际类型,确认它确实是BoxExit的实例,返回true
这就导致两个条件同时成立,执行了var a = 1;的代码。
为什么string的例子结果不同?
你测试的string aa = null;是真正的CLR Null:此时变量aa在CLR中没有指向任何对象,自然不存在类型信息,所以aa is string返回false。这和Unity的"假Null"完全是两回事——Unity的"假Null"是CLR层面仍存在的对象,只是被Unity标记为无效。
如何区分真假Null?
如果要判断一个MonoBehaviour对象是否是真正的CLR Null,可以使用object.ReferenceEquals()方法(这个方法不会被Unity重写):
if (object.ReferenceEquals(mirr, null)) { // 这里才是真正的Null,不会出现is BoxExit为true的情况 }
另外,C#的is null语法也是基于CLR层面的判定,所以:
if (mirr is null) { // 真正的CLR Null才会进入这里 }
额外说明
你的currentEntrance是IEntrance接口类型,而BoxExit实现了该接口同时继承自MonoBehaviour。当你把一个被Unity标记为无效的BoxExit实例赋值给这个接口变量时,Unity的==重写逻辑依然会生效(因为实际对象是MonoBehaviour子类),但is运算符会直接检查对象的实际类型,所以出现了看似矛盾的结果。
内容的提问来源于stack exchange,提问作者vainquit

