如何在C#中实现泛型(可能与C ++和Java相关)?

时间:2014-01-29 19:41:24

标签: c# templates generics compiler-construction

在为我设计的玩具语言编写一个编译器时,我看了一下有关用语言实现泛型的选项(通过搜索现有语言的示例),我开始想知道C#泛型。

我会尝试先描述一下我所理解的内容。如果我误解了任何事情,请随时纠正我。我将使用术语泛型类/类型/模板/定义来引用类似List<T>具体类/类型的内容来引用类似{{ 1}},List<int>

事先就帖子的长度道歉。


C ++ 使用模板进行泛型编程。据我了解,这意味着:

  1. C ++编译器在遇到模板定义时,简单 将其文本(或文本的等价物)保存在内存中。
  2. 然后,每次遇到对(新)具体类型的引用 在代码中,查阅通用模板,文本为 生成请求的具体类型(通过替换类型 具有所请求组合的参数),最后该代码是 编译并添加到二进制文件中。
  3. 模板本身在二进制文件中不可用,因为它只是一个文本表示形式而不是具体类型。只有从中生成的具体类型才会可见。

    (我对这最后一部分不确定 - 如前所述,如果我关闭,请纠正我。)


    Java 使用类型擦除,这意味着仅在编译时检查所有泛型类型参数的类型安全性,然后(如果未检测到类型不匹配),它们全部替换为对{的引用{1}}基类型,有效地为所有具体类型引用重用一个(非泛型)类。


    现在,到实际问题。

    在阅读an interview of Anders Hejlsberg(不是特别关联的,但他的观点相同)之后,他批评了Java的类型擦除,我认为 C#没有使用类型擦除。而且,既然我们可以反思C#中的具体类型,并且我们确实有LINQ这样的东西(它涉及C#的通用功能的相当复杂的用法),我们可以肯定地说C#确实像Java一样使用类型擦除。

    不知道任何其他选项,我认为C#使用类似模板。 不完全是C ++模板(至少我理解它们),因为我们显然可以创建一个具体类型,其泛型版本在另一个程序集中描述,因为我们可以再次反映类型并获取信息关于它。所以,我认为 C#泛型更像模板加上元数据

    在某些时候,我在某处(虽然我无法找到链接)读到C#泛型类实际上是抽象类幕后。显然,这与我认为我所知道的不一致 - 很奇怪。

    我忘记了几个月,但今天我偶然发现a question on SO very similar to this one(不幸的是,没有明确答案)。该问题的作者证明了C#编译器在编译时不会对泛型进行方法解析,即使在编译时可以知道的类型也是如此(使用List<string>方法显示他创造了阴影Object)。

    好的,所以C#generics肯定不是&#34;文本替换加元数据&#34;,正如我原先想的那样。如果是,则在该问题中new的(文本生成的)具体类型将导致编译器以非常不同的方式解析object.GetHashCode调用。

    但相反,C#编译器将其解析为类型只是Test用于泛型类型的所有具体实现包括如果GetHashCode object是非通用代码,则会解析new GetHashCode。这使得它看起来像 C#泛型更接近类型擦除加上元数据 。现在我知道这个术语不太贴切:如果每个具体类的元数据都保留了类型参数信息,它就不是真正的类型擦除 - 但它确实类似于Java将所有内容存储为对象的方法(在至少对于参考类型,它们在低级别基本上是可互换的)并且来回传播。

    我试图想象第三种可能性(正如我所说的那样,我无法找到任何来源 - 所以要带上一粒盐),泛型类表示为抽象类在幕后,每次生成一个新的具体类型时,编译器只是简单地扩展和智能地专门化,但我不能完全理解它在实践中如何工作。例如,泛型类的修饰符sealed的语义必须被移位&#34;允许 类(在程序集中)扩展,但不允许扩展它的子级。一般来说,我认为它会使编译器(也可能是运行时)变得非常复杂,我甚至无法理解。

    那么,如何在C#中真正实现泛型?虽然它们肯定存在差异,但是它们更接近于C ++还是更接近Java?或者是泛型定义真的表示为程序集中的特殊抽象类?或者它可能与我所描述的完全不同?

    我不是在寻找一个特别详细的答案(尽管欢迎)。用简单的术语解释就好了,只要它清楚地突出了C#/ Java / C ++之间的差异,并且至少为我提供了关于C#编译器和运行时如何处理泛型类的理论知识。


    编辑#1:我知道Eric Lippert强调了C ++模板和C#generics in at least one blog post之间的差异,基本上说&#34; C#generics不是模板&#34;但我不知道他们在幕后 的任何解释。


    编辑#2:the linked question 的答案并未解决我提出的问题。该答案简要解释了一个特定的例子或现象,它是底层实现的结果,但绝对不能解释被问及的内容:底层实现是什么。

1 个答案:

答案 0 :(得分:2)

请参阅此处:内部工作方式:http://microsoftdev.blogspot.in/2007/07/how-generics-work.html

并且C ++模板和C#泛型之间的区别在于:

http://msdn.microsoft.com/en-us/library/c6cyy67b.aspx