找回密码
 立即注册
查看: 762|回复: 6

[笔记] Unity 中的 Start、Update 方法是否属于 MonoBehaviour 类?

[复制链接]
发表于 2021-3-26 14:47 | 显示全部楼层 |阅读模式
如果是,为什么在 MonoBehaviour 中看不到这些函数,而且也不是重写函数。我是这么认为的,调用这些函数,都是通过反射实现,也就是说这些函数只是约定好的,通过检测继承 MonoBehaviour 的类中是否存在这些字的方法来调用。我在 Unity Manual 却看到  MonoBehaviour.Start()。还有一些网友贴的源码:
发表于 2021-3-26 14:51 | 显示全部楼层
unity魔改了mono cpp代码,
自己拿csharp类的函数,注意这个函数是cpp代码里面的,类似于函数指针之类的,和csharp代码没啥关系
然后缓存起来,每次引擎cpp需要调用的gameoobject上面的组件时,直接告诉mono虚拟机调用某个csharp函数的cpp代表,绕过了正常的cpp和csharp交互逻辑
所以跟反射啥的都没太大关系,就是引擎魔改mono,改变了cpp和csharp交互方式
这种改法交互性能高,但就是太黑科技了,导致mono升级困难,unity现在自己维护一个mono版本
如果真用csharp语言自带的反射机制,那性能太差了
有点像cpp调用lua里面的函数一样,给个名字,cpp拿到lua函数的index,每次调用时候正常调用
这样调用,和正常函数调用性能差不多,绕过了虚拟机内部一大堆的处理
这种类方法的cache 用于跨语言的函数调用
因为csharp语言运行时有完整的运行时类型信息,所以很方便根据函数名字来找函数指针
发表于 2021-3-26 14:59 | 显示全部楼层
是反射,
    写Start/Update时,并没有特别的override或者new关键字。也不能base.Start()使用Rider写了一个空的Update时,IDE会提示删掉它。这是因为,不被反射到就不会调用,就不会有性能开销。MonoBehaviour类的C#部分在这,直接看就知道了。https://github.com/Unity-Technologies/UnityCsReference/blob/9034442437e6b5efe28c51d02e978a96a3ce5439/Runtime/Export/Scripting/MonoBehaviour.bindings.cs
具体来说,它的反射并不是使用.net库(System.Reflection)来实现的。
我们知道,Unity大致上分为两个部分,大部分核心逻辑使用Cpp开发,之后包装一层C#,把C#接口开放给开发者。
这里的反射的详细做法是,由Cpp在C#的runtime层面反射出相应的方法,并由Cpp集中管理和调用。(如Update之类的方法,并不会每帧反射一次,而是一开始反射完了就直接存起来。)


(网络上流传有unity4.x泄露的源码,可以仅以学习目的去看看实现。(充钱的话也可以看到最新的源码)
发表于 2021-3-26 15:01 | 显示全部楼层
这种没有显式调用的方法叫做魔术方法(magic method)。很多人以为它们都是通过反射(System.Reflection)去调用的,这可能是一个常见的知识误区。
其实是mono或者il2cpp会去检查MonoBehavior里有没有这些魔术方法,有的话就把它们注册进列表。游戏中仅仅简单地遍历列表,执行这些方法。这也就是为什么魔术方法无所谓是public还是private的原因了。
发表于 2021-3-26 15:04 | 显示全部楼层
就是反射,这叫魔 术 方 法
发表于 2021-3-26 15:12 | 显示全部楼层
对的,你没猜错,就是反射来的
发表于 2021-3-26 15:18 | 显示全部楼层
我也好奇过这个问题,然后在StackOverflow上提了个问,然后被删除关闭了
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-12-23 07:41 , Processed in 0.096794 second(s), 25 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表