百科问答小站 logo
百科问答小站 font logo



C#泛型(MSIL)的内部是怎么实现的? 第1页

  

user avatar   rednaxelafx 网友的相关建议: 
      

MSIL自身只需声明和使用泛型类型,而无需关心其实例化;.NET是在运行时由CLR来实例化泛型类型的。

跟前面的回答类似,这里用Dictionary<TKey, TVal>举例。

带有未绑定值的泛型参数的泛型类型称为“开放泛型类型”(open generic type)。这可以看作是原始状态、未填值的“模版”。

所有泛型参数都绑定了具体类型的值的泛型类型称为“闭合泛型类型”(closed generic type 或 closed constructed generic type)。

C# / .NET还有“泛型方法”这么一说,本文略过不提,但处理思路跟泛型类型类似。

对Dictionary<TKey, TVal>来说,

  • Dictionary<TKey, TVal> 是其原始状态的open generic type;
  • Dictionary<String, TVal> 是一个constructed type,但尚未填满所有泛型参数,所以虽然是constructed generic type但还不是closed generic type,而还是一种open状态;
  • Dictionary<String, int> 是一个closed generic type。

CLR在运行时会为一个泛型类型的open generic type和所有constructed type(包括closed与尚未closed的)生成各自独立的元数据(例如MethodTable),用于描述该类型的特征;这些元数据也会有一些共享的部分(例如EEClass)。这样所有泛型类型的反射操作就都可以支持了。例如

注意这个实例化是惰性(lazy)的——只有CLR在运行过程中“遇到”的泛型类型才会对其实例化。

这部分跟C++的泛型类型实例化相似。但这里CLR只是为泛型实例化生成了元数据,还没涉及到代码的特化。

       using System;  class Program {   static void Main()   {     var g = typeof(System.Collections.Generic.Dictionary<,>);     var g1 = g.MakeGenericType(new []{ typeof(string), g.GenericTypeArguments[1] });     var g2 = g.MakeGenericType(new []{ g1.GenericTypeArguments[0], typeof(int) });     Console.WriteLine("{0}, IsGenericType: {1}, IsGenericTypeDefinition: {2}, ContainsGenericParameters: {3}", g, g.IsGenericType, g.IsGenericTypeDefinition, g.ContainsGenericParameters);     Console.WriteLine("{0}, IsGenericType: {1}, IsGenericTypeDefinition: {2}, ContainsGenericParameters: {3}", g1, g1.IsGenericType, g1.IsGenericTypeDefinition, g1.ContainsGenericParameters);     Console.WriteLine("{0}, IsGenericType: {1}, IsGenericTypeDefinition: {2}, ContainsGenericParameters: {3}", g2, g2.IsGenericType, g2.IsGenericTypeDefinition, g2.ContainsGenericParameters);   } }       

输出是:

       System.Collections.Generic.Dictionary`2[TKey,TValue], IsGenericType: True, IsGenericTypeDefinition: True, ContainsGenericParameters: True                           System.Collections.Generic.Dictionary`2[System.String,TValue], IsGenericType: True, IsGenericTypeDefinition: False, ContainsGenericParameters: True                 System.Collections.Generic.Dictionary`2[System.String,System.Int32], IsGenericType: True, IsGenericTypeDefinition: False, ContainsGenericParameters: False     

上面的例子里g是generic type definition,是最初始的open generic type;

g1是constructed generic type但尚未close;

g2是closed constructed generic type。

只有close generic type才可以创建对象实例或执行方法的代码。CLR在为泛型类型的方法/泛型方法JIT编译出native code时采用了代码共享的设计:

  • 泛型参数绑定的值是值类型时,CLR的JIT编译器会为每一个这样的closed generic type / method生成完全特化的native code,不同实例化泛型类型之间不共享代码,这跟C++的模型一样;
  • 泛型参数绑定的值是引用类型时,CLR的JIT编译器会为所有这样的closed generic type / method生成一份共享的native code,而类型特化的信息存在一个额外的表里面由每个实例化泛型类型自己带着。这样就共享了大部分内容,只带有少量数据不共享。这些不共享的数据主要用来支持诸如new T()、typeof(T)、(T)、is T、as T之类的运算。这比C++的模型稍微复杂一点,优点是共享了更多东西(代码),缺点是在需要对T特化的地方可能会稍微慢一点(但大部分对引用的操作其实都不需要对T特化,所以实际性能并不会受太大影响)。

当然,还得考虑到带有多个泛型参数的泛型类型的情况,但都可以套用上面两条规则去推导。

这么大的功能不可能没有论文,MSR有一篇论文专门讨论CLR的泛型设计与实现:

Design and Implementation of Generics for the .NET Common Language Runtime

,请仔细阅读参考。




  

相关话题

  为什么没有新的支持底层达到类似C++这种程度,而易用性达到C#的语言出现? 
  .net为什么要将应用程序编程语言统一? 
  有没有什么工具可以帮助理解源代码的? 
  既然在语言层面上 Java 要落后于 C#,那为何国内 Java 架构到处都是? 
  C#新启线程导致主线程卡住的问题? 
  如何评价微软新推出的 .NET 5? 
  关于自己写的ASP.NET MVC控件找不到视图的问题? 
  如何评价"Null reference - my billion-dollar mistake"? 
  ASP.NET MVC 如果全部用异步 Controller,会有什么效果?会成为高吞吐量,高并发的网站么? 
  c#匿名委托获取自身的方法? 

前一个讨论
HTTPS体系中若攻击者将自己公钥上传CA得到签名,并将两者一起用于篡改证书的中间人攻击会怎样?
下一个讨论
Windows 10 数字许可证是否会影响微软应用商店自动下载第三方应用?





© 2024-12-26 - tinynew.org. All Rights Reserved.
© 2024-12-26 - tinynew.org. 保留所有权利