主要内容来源

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. Canvas恢复布局

    package com.loaderman.customviewdemo; import android.content.Context; import android.graphics.Canvas ...

  2. HTML5Audio/Video全解(疑难杂症)

    1.mp4格式视频无法在chrome中播放 Chrome浏览器支持HTML5,它支持原生播放部分的MP4格式(不用通过Flash等插件).为 什么是部分MP4呢?MP4有非常复杂的含义(见http:/ ...

  3. docker之redis使用

    #拉取redis > docker pull redis:latest latest: Pulling from library/redis 8d691f585fa8: Pull complet ...

  4. JVM参数详细说明

    JVM参数详细说明   答: 下面红色部分是常用参数 -XX:CMSInitiatingPermOccupancyFraction:当永久区占用率达到这一百分比时,启动CMS回收-XX:CMSInit ...

  5. QML小例子【QML工程里信号与槽】

    1.效果 代码参考B站视频:https://www.bilibili.com/video/av36584062 功能:点击左边,会发出信号,右边会有个颜色动画,然后计数+1 2.分析: 一共有两个对象 ...

  6. LVS搭建负载均衡集群(二)——DR模式

    (1).DR模式和TUN模式介绍 Direct Routing(直接路由):director分配请求到不同的real server.real server处理请求后直接回应给用户,这样director ...

  7. WinSCP 上传文件至Cetos 7 后用户无权限

    WinSCP是一个支持SSH的SCP文件传输软件. 可以用Windows环境向Linux环境传输文件,今天给新的Elasticsearch 服务器(cetos 7 )部署新的集群节点的时候,发现传输后 ...

  8. VLOOKUP函数 from Excel

    1.VLOOKUP函数是Excel中的一个纵向查找函数,它与LOOKUP函数和HLOOKUP函数属于一类函数,在工作中都有广泛应用,例如可以用来核对数据,多个表格之间快速导入数据等函数功能.功能是按列 ...

  9. Spring 控制器层如何启用验证?

    1.示例代码 @PostMapping("/adduser") public String addUser(@Valid User user,BindingResult bindi ...

  10. 使用自定义Comparator对TreeSet中的数据进行多条件排序

    代码记录(需求:根据店铺等级和店铺到某个点的距离进行排序,其中店铺等级由高到低,距离由近及远) 需要排序的对象Store,Store.java package com.zhipengs.work.te ...