[toc] https://www.lfzxb.top/what-causes-csharp-invoke-method-by-reflection-slowly-and-how-to-solve-it/
# C# 反 射为什么这么慢
# 反射的设计初衷
- 在
运行时
非常快的访问我们所需要的代码信息 - 在
编译时
非常直接的访问生成代码所需的信息 - 垃圾回收器 / 计算堆栈能够在不对程序加锁 / 分配内存的情况下访问必要的信息
- 能极大减少一次性需要加载的类的数量
- 能极大减少给定类型加载时所需要加载的额外类型数目
- 类型系统数据结构必须在 NGEN 映像中是可存储的
我们可以看到,它只强调了最少依赖加载,并 没有说我们可以直接从元数据获取所有CLR数据类型
。也 没有说所有的反射用法都是快的
,只能说反射获取一些信息很快。MethodTable 的数据被分为 "热" 和 "冷" 两种数据结构来提升工作效率和缓存利用率,MethodTable 本身只存储那些在 程序稳定状态(是否可以翻译为一般运行时)
下被需求的 "热" 数据。EEClass 存储那些只在 类型加载时
, JIT编译时
, 反射时
需要的 "冷" 数据。
# 反射是如何工作的呢
那么到底是哪里让反射花费了额外的时间呢?我们来看看一次反射调用它所经历的非托管 / 托管代码的调用栈。 - System.Reflection.RuntimeMethodInfo.Invoke (…):calling System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal (…)。C++ MethodInfo 源码链接 - System.RuntimeMethodHandle.PerformSecurityCheck (…):calling System.GC.KeepAlive (…)。C++ reflectioninvocation 源码链接 - System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal (…):calling stub for System.RuntimeMethodHandle.InvokeMethod (…)。C#MethodInfo 源码链接 - stub for System.RuntimeMethodHandle.InvokeMethod (…):大部分工作是在这里完成的,它的源代码超过了 400 行。C++reflectioninvocation 源码链接
# 获取方法信息
在你反射调用一个字段 / 属性 / 方法之前,你不得不获取 FieldInfo/PropertyInfo/MethodInfo 来处理,就像这样
1 | Type t = typeof(Person); |