Unity 自定义"=="操作符 [翻译来源blogs.unity3d,2014/05]

主要内容来源

https://blogs.unity3d.com/cn/2014/05/16/custom-operator-should-we-keep-it/

在我们代码里,如果有这样的代码:

if (myGameObject == null)

那Unity底层做了什么? (事实上,除了GameObject,继承自UnityEngine.Object的类都是这样的)

在Unity的Editor运行时,特殊实现了这一类继承自UnityEngine.Object的 "==" 操作符

主要有两个原因:

1. 在Editor下,如果对一个Monobehaviour的字段赋值为null, Unity并不会真的把这个字段置为null,而是用一个 "fake null" 对象代替,并且在这个特殊对象里记录了一些信息 [备注1]

这样的好处是,当你尝试去访问这个字段时,并不是得到一个缺乏具体指示的NullReferenceException报错,而是一个具有提醒信息的空抛错: 例如: MissingReferenceException: The object of type 'XXX' has been destroyed but you are still trying to access it"

并且Unity会在Inspector界面上高亮发生这个错误的GameObject. 这样是为了让开发者的开发查错更加容易

2. 由于Unity是C/C++引擎,在我们用C#开发,去访问一个GameObject时[备注2],实际得到的是一个C#对象(wrapper object),而这个物体的实际信息,包括name, HideFlags, Components都是在C++ 的本地对象(native object)里.C# wrapper object存储了指向native object的指针.

这些native object(包括GameObject本身及其components)的生命周期都是托管(explicitly managed)的,在切场景或者调用Object.Destroy(myObject)时被销毁,而C# wrapper object是通过C#  gc管理的

这就可能会出现.一个C# wrapper object仍然存在但是其对应的C++ object已经被销毁的情况. 当你去拿C# wrapper object判空时, 内部实现的"=="运算符会返回true,尽管在实际上C#对象是仍然存在的.

虽然基于上面两个原因,Unity引擎自定义了"=="运算符有其合理之处.但是这也导致了以下几个负面影响:

1. 这是有悖常理的(C# wrapper object仍然存在,拿其判空却为true)

2.拿两个UnityEngine.Objects对比或者和null对比的效率要低于我们的期待

3."=="运算符是不线程安全的,所以你不能在非主线程对比objects. (这一点Unity会去修复)

4.会导致??操作符表现不一致(It behaves inconsistently with the ?? operator,). 因为??操作符内部会做真正的C#对象的空检查,不会调用到Unity自定义的空检查函数

所以会导致 ?? 操作符和 == 操作符的结果矛盾

很多用户可能会没有意识到这个"=="的副作用.[备注3]

综合上面的积极和消极影响,考虑到已有项目的兼容和升级成本,Unity也在纠结是否拿掉这个自定义的"==".

备注

[1] 这种fake null 对象只会在Editor下使用,所以在你使用GetComponent查询一个不存在的Component时会看到一个C#内存分配,这是因为我们在内部创建Fake null Object时生成了一个自定义的警告String文本.这个内存分配不会出现在构建后的游戏中

这也是一个很好的例子证明: 你应该始终在实际运行的独立运行环境(standalone player)或者手机运行环境(mobile player)上要做性能分析,而不要在Editor下做Profile, 这是因为我们在Editor环境下做了大量的额外安全性检查,容错检查,资源使用检查等,牺牲了一些性能,这也是为了让你的开发变的轻松, 所以如果要分析内存分配的性能问题,永远不要在Editor下做Profiler,要始终在构建的游戏中进行Profiler

[2]这个规则不仅仅适用于GameObject,而且还适用于所有继承自UnityEngine.Object的类

[3]自己作为Unity的官方技术人员在做性能优化时都出现过忽视该空检查的副作用的情况

以至于目前为止,Unity还是没有去掉该自定义"=="

原文地址:https://www.cnblogs.com/wmalloc/p/9139640.html