主要内容来源

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还是没有去掉该自定义"=="

Unity 自定义"=="操作符 [翻译来源blogs.unity3d,2014/05]的更多相关文章

  1. (Unity)Unity自定义Debug日志文件,利用VS生成Dll文件并使用Dotfuscated进展混淆,避免被反编译

    Unity自定义Debug日志文件,利用VS生成Dll文件并使用Dotfuscated进行混淆,避免被反编译. 1.打开VS,博主所用版本是Visual Studio 2013. 2.新建一个VC项目 ...

  2. RxJava(10-操作符原理&自定义操作符)

    转载请标明出处: http://blog.csdn.net/xmxkf/article/details/51791120 本文出自:[openXu的博客] 目录: 自定义创建操作符 数据序列操作符li ...

  3. Swift 4.0 高级-自定义操作符

    在Swift语言中,常见的操作符有+.-.*./.>.<.==.&&.||等等,如果不喜欢,你也可以定义自己喜欢的操作符. 操作符类型 中置运算符(infix operat ...

  4. https://blog.newrelic.com/2014/05/02/25-php-developers-follow-online/

    w https://blog.newrelic.com/2014/05/02/25-php-developers-follow-online/ 1. Rob Allen. Zend Framework ...

  5. new操作符(翻译自mozilla.org)

    翻译自:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new new操作符可以实例化一个用户自 ...

  6. 【Unity Shaders】Reflecting Your World —— Unity3D中简单的Cubemap反射

    本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...

  7. Unity 自定义编辑窗体之ScriptableWizard

    当我们在编辑界面要批量设置游戏资源的时候,就需要从UnityEditor里面继承,实现自己的窗口类. 所幸UNITY提供了最简单的一个自定义窗体类,我们直接往上扔public类型的属性就好,提供了确认 ...

  8. unity, 自定义类中使用print

    在unity脚本中自定义c#类,而且不继承MonoBehaviour的话,若还想在其中使用print函数,可以用MonoBehaviour.print(...).

  9. Unity 自定义Inspector面板时的数据持久化问题

    自定义Inspector面板的步骤: Unity内创建自定义的Inspector需要在Asset的任意文件夹下创建一个名字是Editor的文件夹,随后这个文件夹内的cs文件就会被放在vstu生成的Ed ...

随机推荐

  1. React之概述(待续)

    原文链接 MDN上有关JavaScript的内容 箭头函数, 类, 模板字符串, let, const Babel REPL

  2. 阶段5 3.微服务项目【学成在线】_day18 用户授权_05-方法授权-方法授权测试

    这是我们课程的服务里面 加了授权的方法 重启课程管理的服务 首先需要登陆 在redis复制token 访问课程列表 用最新复制的令牌 最新token可以 调用teachplan方法 调用 一个没加注解 ...

  3. 总结Lock和synchronized的区别

    1. Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现,Lock是代码层面的实现. 2. Lock可以选择性的获取锁,如果一段时间获取不到, ...

  4. 123457------com.threeapp.quWeiKaTongPinTu01----趣味卡通拼图游戏

    com.threeapp.quWeiKaTongPinTu01----趣味卡通拼图游戏

  5. tornado之自定义form表单验证

    直接上链接吧:银角的地址 源码下载链接:点我点我点我...

  6. linux计划任务以某个用户身份执行

    # Example of job definition: # .---------------- minute (0 - 59) # |  .------------- hour (0 - 23) # ...

  7. 【Leetcode_easy】709. To Lower Case

    problem 709. To Lower Case solution1: class Solution { public: string toLowerCase(string str) { stri ...

  8. python:一行代码实现局域网共享文件

    其实就是使用python内置的一个模块http server 在python2中是下面这样的 python -m SimpleHTTPServer 80 解释下上面的参数,-m表示让python使用一 ...

  9. Docker 容器资源隔离 namespace(十)

    目录 一.简介 Linux Namespace的6大类型 二.Mount Namespace 三.IPC Namespace 四.Network Namespace 五.UTS Namespace 六 ...

  10. 最新 游族网络java校招面经 (含整理过的面试题大全)

    从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿.游族网络等10家互联网公司的校招Offer,因为某些自身原因最终选择了游族网络.6.7月主要是做系统复习.项目复盘.Leet ...