如何通过JIT编译器编译泛型?

时间:2011-03-17 16:46:44

标签: c# generics compiler-construction jit

我知道泛型是由JIT编译的(就像其他所有东西一样),与编译代码时生成的模板形成对比。
问题是可以使用反射在运行时创建新的泛型类型 这当然会影响通用的约束。哪个已经通过了语义解析器。

有人能解释一下这是如何处理的吗?究竟发生了什么?
 (代码生成和语义检查)

2 个答案:

答案 0 :(得分:36)

我建议阅读Generics in C#, Java, and C++: A Conversation with Anders Hejlsberg

  

Qn 1.泛型如何被编译   JIT编译器?

从采访中:

  

Anders Hejlsberg:[...]   在CLR [公共语言运行时]中,   当您编译List或任何其他时   泛型类型,它编译为IL   [中间语言]和元数据   就像任何普通类型一样。 IL和   元数据包含其他   知道有类型的信息   参数,当然,但在   原则,泛型类型编译   就像任何其他类型的方式一样   编译。在运行时,当你的   应用程序首次参考   到列表,系统看起来   如果有人已经要求   List<int>。如果没有,它会进入   JIT List<T>的IL和元数据   和类型参数int。 JITer,   在JITing IL的过程中,也是   替换类型参数。

     

[...]

     

现在,我们接下来要做的就是所有类型   有价值的实例化   类型 - 例如List<int>, List<long>, List<double>, List<float> - 我们创建了一个   可执行本机的唯一副本   码。所以List<int>获得了自己的代码。   List<long>获取自己的代码。   List<float>获取自己的代码。对全部   我们共享代码的引用类型,   因为它们具有代表性   相同。这只是指针。


  

Qn 2.事情是新的通用类型   可以使用在运行时创建   反射。哪个当然可以影响   通用的约束。哪一个   已经通过语义解析器。   有人可以解释这是怎么回事   处理?

本质上,IL保留了泛型类型的高级视图,它允许CLR在运行时检查“动态构造的”泛型类型的约束,就像C#编译器可能对C#源中的“静态构造”类型一样-code在编译时。

这是另一个片段(强调我的):

  

Anders Hejlsberg:[...]   有了约束,你可以提升它   动态检查你的代码和   在编译时可以验证   或加载时间。当你说K必须时   实现IComparable,一对   事情发生。在K的任何值上,   你现在可以直接访问了   没有强制转换的接口方法,   因为在程序中的语义   它保证会实施   那个界面。每当你尝试和   创建该类型的实例化,   编译器会检查任何类型   你给K参数实现了   IComparable,否则你得到一个编译   时间错误。 或者如果您正在使用它   反思你得到例外。

      Bruce Eckel:你说过编译器和   运行时。

     

Anders Hejlsberg:编译器检查   它,但你也可以这样做   运行时用反射,然后是   系统检查它。正如我之前所说,   你在编译时可以做的任何事情,   你也可以在运行时使用   反射。

答案 1 :(得分:2)

参考类型泛型都变为相同类型;值类型泛型实例化单独

这是因为引用类型实际上只是Object个引用(4或8个字节),而值类型是不同的,由于堆栈布局不同等原因,单个代码不能处理它们。因此使用值类型实例化泛型类型的多个副本将大量增加内存使用量,而使用引用类型实例化多个副本则不会。