首页 > 解决方案 > 为什么 C# 允许将泛型数组与所有类型的模式进行匹配?

问题描述

我有一个泛型类型的数组T,我想检查长度是否为 0。但是,我打错了,而不是Array.Length is 0我输入了Array is 0。当我注意到这个错字时,我想知道为什么它没有给我一个编译时错误,当我使用任何具体类型的数组(如string, int, object, 甚至dynamic. 显然,无论数组的底层类型是什么,数组都不能int为零值,所以这是值得怀疑的。我尝试了各种其他 int 文字、字符串文字,我什至尝试了小于和大于模式,所有这些都奏效了。我尝试更改数组的维度或可空性(因为我的原始示例是 a T[,]?),我什至尝试向T泛型类型,但这些都没有改变任何东西。

是否存在这些模式实际上可以匹配的特殊情况(即使我无法想象,因为它们仍然只是数组),还是编译器错误?如果是后者,是什么原因造成的?


由于有人要求提供代码,这是一个简单的测试,它给了我相同的结果:(假设 T 是任何泛型类型)

T[] array = new T[42];
// You can assign anything here
// Only thing that matters is that the variable is a T[] with any number of dimensions
if (array is 0 or "test") Console.WriteLine("This shouldn't even compile")

标签: c#arrayspattern-matching

解决方案


我认为这是C# 7.1中以下规范更改的结果:

现有 C# as 运算符的规范允许在操作数的类型和指定类型之间没有任何一个为开放类型时的转换。但是,在 C# 7 中,类型标识符模式需要在输入类型和给定类型之间进行转换。

我们建议放宽这一点,将表达式更改为类型标识符,除了在 C# 7 中允许的条件中允许之外,在允许作为类型的表达式时也允许。具体来说,新案例是表达式的类型或指定类型是开放类型的情况。

改变自己:

左侧的静态类型和给定类型的某些组合被认为是不兼容的,并导致编译时错误。如果存在标识转换、隐式引用转换、装箱转换、显式引用转换或从 E 到 T 的拆箱转换,或者如果 E或 T 是开放类型。如果类型 E 的表达式与其匹配的类型模式中的类型不兼容,则这是一个编译时错误。

由于此更改,如果左侧is是开放的泛型类型(您的问题就是这种情况) - 那么它被认为是他们所谓的“模式兼容”与右侧的任何内容。

但是,特定的泛型类型如string[]违反规范中提到的其他限制,因此与 int 不“模式兼容”,因此会导致编译错误。

T[] array = new T[10];
bool test = array is int; // that's fine with this proposal, since left sid e is open type

现在有关您正在使用的常量模式is 0的文档 ( ) 说:

当输入值不是开放类型时,将常量表达式隐式转换为匹配表达式的类型;如果输入值的类型与常量表达式的类型不兼容,则模式匹配操作是错误的。

正如我们所知道的,开放类型(T[]T解析的)泛型数组与 int 模式兼容,因此编译器对您的表达式很好,而string[](或任何其他封闭的泛型数组)不兼容模式并导致错误。

您可以在第一个链接中查看动机部分,了解他们决定以这种方式更改规范的原因。


推荐阅读