[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
2
Type t = typeof(Person);
FieldInfo m = t.GetFiled("Name");