主要内容来源

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. Mybase解决保存文件后再打开不能修改编辑

    1.问题复现 2.解决方式 3.可以修改编辑

  2. PHP重建数组的索引

    sort() array_merge()跟一个空数组合并都可以重建索引数组的键(key)

  3. 利用PHP应用程序中的远程文件包含(RFI)并绕过远程URL包含限制

    来源:http://www.mannulinux.org/2019/05/exploiting-rfi-in-php-bypass-remote-url-inclusion-restriction.h ...

  4. .Net Core 定时器Quartz

    最近因为项目需要用到了Quartz,下面简单记录一下. 一.首先需要安装Quartz. 二.定义一个执行的Job类,实现IJob接口,接口有一个方法Execute,用来执行定时任务的实现内容. pub ...

  5. 【VS开发】【数据库开发】libevent简单入门和介绍

    libevent是一个基于事件触发的网络库,memcached底层也是使用libevent库,今天学习下. 总体来说,libevent有下面一些特点和优势: * 统一数据源, 统一I/O事件,信号和定 ...

  6. idea查看一个接口的子接口或实现类的快捷键

    ctrl+h 先选中类或接口,再按ctrl+h

  7. [转帖]8个优秀Docker容器监控工具,收藏了

    8个优秀Docker容器监控工具,收藏了 Docker是目前使用最广泛的容器之一,但它并不总是像物理硬件一样可见.而使用docker容器监控工具有助于消除这种透明度的缺失.以下介绍8种优秀Docker ...

  8. 前端通过js获取手机型号

    ###前段通过js获取手机型号 需求: 用户登录后记录当前的手机型号并记录 插件: mobile-detect.js插件地址 mobile-device-js插件地址 使用步骤: 获取UA信息-> ...

  9. ASP.NET Core 过滤器

    继承Attribute,IActionFilter实现自己的过滤器类,并且在Startup,mvc服务中注入. 全局都会过滤,在任意一个controller,action执行前和执行后都会过滤一次 通 ...

  10. Nuget常用命令(转)

    转自:https://www.cnblogs.com/xcsn/p/6259853.html CMD将nuget升级到最新版本:nuget update -self 一.安装 1.安装指定版本类库in ...