显然反射是一个非常广泛的主题,但让我们举一个简单的例子:“is”运算符(A 是 B)。它实际上需要 CLR 做什么?要查看程序集的元数据,请找到类型 A,向上遍历其继承层次结构并查看 B 是否在其中某处。
现在,这不是 CLR 的所有标准工作吗?我的意思是,CLR 在运行时一直在非反射代码中进行类型检查。每当您调用方法或为参数赋值时,CLR 必须在运行时检查所分配对象的类型是否与其指定的参数或变量匹配。
那么是什么让反射(我的意思是简单的运算符,例如“is”或“as”)相对昂贵?
is运算符与检索类的类型一样昂贵。最大的区别在于何时产生该成本。在is运算符的情况下,当 JIT 编译器在编译代码时从程序集中检索元数据时,就会发生这种情况。这发生在您执行代码之前,因此很可能是您在分析时没有观察到的成本。或者将其视为不可避免的开销,它是。一旦完成,在循环中使用 is非常便宜,因为抖动已经将指向类型方法表的指针值(也称为“类型句柄”)直接编译到机器代码中。无需再次查找类型。
反射不是这种情况,它不会提前运行。您将衡量在磁盘上查找程序集的成本,以及在执行程序集文件时从程序集文件中调入元数据的页面错误。这可能是相当大的,磁盘很慢。之后再次找到元数据缓存槽的成本。