【问题标题】:C# generics: does compiler creates only one specialized generic type for different reference types? [duplicate]C# 泛型:编译器是否只为不同的引用类型创建一种专门的泛型类型? [复制]
【发布时间】:2020-01-05 13:38:51
【问题描述】:

Generics in the Run Time (C# Programming Guide) 中据说确实如此,这让我感到惊讶。我一直认为,无论它是值类型还是引用类型,它都会为每个不同的类型参数创建一个单独的专用类型。也许是因为(如果我没记错的话)这就是我使用 C++ 时的样子。

无论如何,如果 C# 编译器将所有引用类型都视为一个专用泛型类中的指针,我无法理解它如何知道它处理的类型。例如,当List<T> 返回一个项目时,它应该知道它返回的类型,因此应该有一个专门的方法/类。它是如何工作的?它是否只为系统泛型集合或任何泛型类(包括自定义类)创建单个专用类型?

【问题讨论】:

  • 你可以看看这个线程Where are generic methods stored值类型有不同的大小,所以每个值类型都有一个单独的构造泛型类。而且引用类型只有一个泛型类,因为大小相同
  • 谢谢!如果我理解正确,对于每个引用类型,仍然会生成一个专门的类型(因为它可以通过反射获得),但在内部只有一个专门的类型将任何引用视为指针。所有这些技巧都发生在运行时(而不是编译时)。
  • 是的,在 C# 中,泛型是在运行时评估的,而不是在编译时评估
  • 您的问题的字面答案(也可以在标记的重复项中找到)是 不,编译器不会只创建一种类型来处理用作类型参数的所有不同引用类型泛型类型。 具有不同类型参数的泛型类型的每次使用都会为该参数生成不同的新具体类型。但是,对于引用类型确实,最终实现该类型的本机代码在所有类型参数之间共享。编译类型保证类型安全,T的值都是引用,所以代码可以共享。

标签: c# generics


【解决方案1】:

我想稍微深入地回答一下。

首先,让我们问这个问题。

CLR如何对待泛型方法?

当使用泛型类型参数的方法进行 JIT 编译时,CLR 会获取方法的 IL,替换指定的类型参数,然后创建特定于在指定数据类型上操作的该方法的本机代码。它被称为代码爆炸

CLR 以何种方式生成本机代码?有什么规定吗?

CLR 不断为每种方法/类型组合生成本机代码。如果任何类型参数是值类型,CLR 必须生成专门针对该值类型的本机代码。原因是值类型的大小可能不同。

但是,对于引用类型CLR 有一些优化。 CLR 认为所有引用类型参数都是相同的。同样,代码可以共享。例如,CLR 为List<String> 的方法编译的代码可以用于List<Stream> 的方法,因为StringStream 都是引用类型。事实上,对于任何引用类型,都将使用相同的代码。 CLR 可以执行此优化,因为所有引用类型参数或变量实际上只是指针。

这种解释的来源是 Jeffrey Ritcher 的书。 (CLR via C#)

现在我们来回答你的问题:

我不明白 C# 编译器如何知道它处理的是什么类型?

您已经知道 CLR 使用指针作为引用类型的泛型参数。当然,该指针指向堆上的某个对象。而且堆上的每个对象都需要一些额外的成员。其中之一称为类型对象指针。该指针指向存储在堆上的相应Type 对象。而且,CLR 使用该信息来获取对象的类型。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-06-12
    • 2019-11-30
    • 2010-10-22
    • 1970-01-01
    • 1970-01-01
    • 2019-06-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多