何时在C#中进行通用定义和实例化的类型检查?

时间:2017-09-18 21:42:56

标签: c# generics programming-languages computer-science

在C#中,

  • 是否在编译时对泛型定义进行类型检查?

  • 是否在运行时检查泛型的实例化?

感谢。

上面的问题让我在Nutshell中理解C#中的粗体引号:

  

然而,使用C#泛型,生成器类型(即,开放类型,如   List)可以编译成一个库(如mscorlib.dll)。   这是因为生产者和生产者之间的合成   生产封闭类型的消费者实际上不会发生   运行

     

要深入研究为什么会出现这种情况,请考虑使用Max方法   C#,再一次:

static T Max <T> (T a, T b) where T : IComparable<T>
  => a.CompareTo (b) > 0 ? a : b;
     

为什么我们不能像这样实现它?

static T Max <T> (T a, T b)
  => (a > b ? a : b);             // Compile error
     

原因是Max需要编译一次并且适用于所有人   可能的T值。编译不能成功,因为有   对>的所有值T没有任何意义 - 事实上,不是   每个T甚至都有>运算符。

我也有the same question for Java

3 个答案:

答案 0 :(得分:1)

在编译时检查泛型定义和实例化。此外,它们可以单独检查。与C ++不同的是,你可能在模板中发现错误,直到你以后尝试实例化它,在C#中,在编译声明本身时,会发现泛型声明中的任何编译错误。

C ++缺乏的神奇功能是constraints。这就是示例向您展示的内容。

定义泛型方法或类时,可以对类型参数设置约束。这些限制允许哪些实例化,但也决定了你可以在泛型声明的主体中利用哪些操作。

编译声明时,编译器会检查您是否对其约束条件不允许的类型参数执行任何操作。因此,例如,您在此处收到错误:

T Foo<T> (T a) => a.CompareTo(b);

您尝试拨打CompareTo a,其类型为T。编译器无法知道用户只会使用具有该方法的类型来实例化Foo,因此它悲观地假设它可以使用不具有该类型的类型进行实例化,并阻止您编译此声明。 / p>

将其更改为:

T Foo<T> (T a) where T : IComparable => a.CompareTo(b);

现在它知道T 的每个实例都必须有一个CompareTo()方法,所以它会编译它。

稍后当有人试图用某种类型实例化Foo时,如果该类型没有实现IComparable,则会出现编译错误。由于该方法说&#34;您只能使用实现IComparable&#34;的类型,编译器会确保它们满足该约束。

答案 1 :(得分:0)

类型检查的主要目的是在编译时检测错误,即在使用软件之前。这可以防止错误到达用户。

在编译时检查C#泛型类型。请参阅Benefits of Generics

在某些情况下,C#也会在运行时进行类型检查,但是为了防止错误为时已晚 - 应用程序已经在运行并正在使用。

答案 2 :(得分:0)

好吧,编译器在编译时检查泛型参数的用法并生成“泛型感知类型”。在IL中有关于这种操作的特别指示。 C#编译器使用泛型定义中的任何限制来允许对泛型参数进行操作。所以,回答第一个问题 - 是的,它确实检查了泛型参数类型。在定义基于泛型类型的常规类型时,检查类型是否满足所有限制,如果是,则生成另一种类型,内部类型,用于泛型类型和参数的组合。编译器将使用该生成的类型用于组合泛型类型及其参数类型的所有其他实例,但是这个第二阶段发生在运行时请求使用参数创建特定泛型类型时。 创建类型时,它只是常规的,而不是泛型类型事件,它的基类是通用的,编译器使用常用方法来检查与此类型的任何实例相关的类型。