【问题标题】:Why is specialization in C# generics limited?为什么 C# 泛型的专业化受到限制?
【发布时间】:2017-09-19 16:03:24
【问题描述】:

问题"What is reification?"对C#的泛型有评论:

类型信息得到维护,通过使用反射检查类型参数,在一定程度上允许专业化。然而,专业化的程度是有限的,因为泛型类型定义是在任何具体化发生之前编译的(这是通过根据类型参数的约束编译定义来完成的 - 因此,即使没有特定类型参数,编译器也必须能够“理解”定义)。

  • “专业化”是什么意思?是不是和用特定类型参数实例化泛型类型不一样?

  • “专业化程度有限”是什么意思?

  • 为什么它是“泛型类型定义在任何具体化发生之前编译的结果”?

【问题讨论】:

  • 为什么不问作者?
  • 评论不是详细解释的好地方。
  • 我不理解“太广泛”的投票无法结束这个问题。如果有的话,更容易争论这个问题过于狭窄,因为它寻求澄清与 C# 相关的一个特定答案的一部分。郑重声明,我认为这个问题既不太宽也不太窄。

标签: c# generics programming-languages


【解决方案1】:

“专业化”是什么意思?是不是和用特定类型参数实例化泛型类型不一样?

作者在其专门针对 Java 泛型的答案部分中解释了

泛型类型的特化[是]为任何特定泛型参数组合使用专门源代码的能力。

换句话说,如果泛型类型参数属于特定类型,则它是一种执行特殊操作的能力。当您将类型实例化为 List<bool> 时,提供一个 List<T> 的实现将单个元素表示为位,这将是特化的一个示例。

“专业化程度有限”是什么意思?

作者的意思是虽然你可以写类似的东西

if (typeof(T) == typeof(bool)) {
    ...
}

您响应类型参数组合的能力是有限的,因为对类型组合的任何决定都必须在运行时做出。

为什么它是“在任何具体化发生之前编译泛型类型定义这一事实的结果”?

因为具体化是在 CLR 中完成的,所以在 C# 编译器不存在之后。编译器必须为 CLR 生成一个泛型类型定义,以用作“模板”来为泛型类的实例创建封闭构造类型。

【讨论】:

  • 这个答案是我的想法。我使用术语“专业化”不是为了将类型参数应用于泛型定义,而是为了某些特殊类型具有不同的代码路径。您可能想要这样做的原因通常与性能有关 - 例如,您知道如果您对待几种类型的方式与对待其他类型的方式不同,那么一段代码会更有效率,因此您希望提供不同的执行路径为他们。
  • 如this answer和我在this other question的回答中所述,泛型代码的解析发生在C#编译器一侧,而实际泛型参数的应用发生在CLR JIT 编译器。这有一些含义,例如 C# 重载解析必须发生在 C# 编译器端,因此您不能利用重载从泛型代码分派到专用路径。相反,您必须先执行if,然后执行typeof,然后进行强制转换,然后调用专用代码。并且在构建通用定义时需要知道这些专门的代码。
  • 这就是我所说的“有限”。为了清楚起见,我在回答中没有使用“有限”的负面含义。 “较少受限”的泛型特化选项(例如使用 C++ 模板,在应用泛型参数之后发生重载决议)有其自身的优势和自身的一系列问题。
  • @TheodorosChatzigiannakis 非常感谢!对于 Java 的泛型,在您对另一篇文章的回复中,“泛型类型的专门化(对任何特定泛型参数组合使用专门的源代码的能力)非常有限”。是因为在编译时已删除类型参数,因此无法进行反射吗?在 Java 中,由于泛型代码的解析和实际泛型参数的应用(即类型擦除,如果我是正确的)都发生在编译时,Java 的重载是否提供泛型类型的“特化”?
  • @Ben Java 泛型不可能重载,因为所有泛型类型都被删除为java.lang.Object 或泛型约束中指定的类型。您仍然可以将 Class<T> 传递给泛型方法或构造函数以启用基于反射的特化,但这样做的机制是惯用的,即它不是内置于语言中的。
【解决方案2】:

我认为意思如下:

当您定义泛型类型时,例如MyGenericType<T> 您的定义必须对 T 的任何值有意义,因为泛型类型是在您在特定实现中实际使用它之前编译的(“专业化程度是有限的,因为泛型类型定义在任何具体化发生之前编译”)。

稍后,当您实际使用MyGenericType<int> 时,编译器/jit 将创建一个新类,该类几乎是MyGenericType<T>,每次提及T 时都会替换为int。这就是物化的过程。这意味着在运行时,您可以使用泛型类型使用 int 的事实,但是您使用它(专业化)的能力是有限的,因为当您定义 MyGenericType<T> 时您不知道这一点。

【讨论】:

    【解决方案3】:

    专业化用作泛化的反义词。创建泛型类型时,您概括了类型定义。当你用一个类型初始化它时,你特化了编译的泛型类型,以便能够在运行时创建该类型的对象。

    IL 编译泛型类型。在运行时,这个编译的泛型类型与特定的类型参数组合以产生指定类的对象。

    是的,特化与在运行时使用特定类型参数实例化泛型类型相同。

    使用泛型,come constraints which basically fix the scope of generic type。您可以通过定义 T 可以是结构、类或必须具有某些特定的基类等来判断这一点。您不能创建泛型类型上定义的约束不允许的类实例。

    如果满足泛型类中的约束,您可以使用 int、string 或其他类初始化相同的泛型类型定义。 它不能用 T 直接创建类的对象,还没有被定义的类型(原始类型,如 int、string 或您的自定义类或接口)替换,并且您的代码应该与作为 T 传入的类型兼容去工作。

    参考(来自您上面提到的同一问题的链接):

    NET Generics and Code Bloat

    Generics are not templates (as in C++)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-04-21
      • 2014-10-08
      • 1970-01-01
      • 2021-02-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多