为什么 C# 允许将泛型数组与所有类型的模式进行匹配?

Why does C# allow matching a generic array against patterns of all types?

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

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


由于有人要代码,所以这是一个简单的测试,结果相同: (假设 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# 7.1 中以下 specification change 的结果:

The specification for the existing C# as operator permits there to be no conversion between the type of the operand and the specified type when either is an open type. However, in C# 7 the Type identifier pattern requires there be a conversion between the type of the input and the given type.

We propose to relax this and change expression is Type identifier, in addition to being permitted in the conditions when it is permitted in C# 7, to also be permitted when expression as Type would be allowed. Specifically, the new cases are cases where the type of the expression or the specified type is an open type.

改变自己:

Certain combinations of static type of the left-hand-side and the given type are considered incompatible and result in compile-time error. A value of static type E is said to be pattern compatible with the type T if there exists an identity conversion, an implicit reference conversion, a boxing conversion, an explicit reference conversion, or an unboxing conversion from E to T, or if either E or T is an open type. It is a compile-time error if an expression of type E is not pattern compatible with the type in a type pattern that it is matched with.

作为此更改的结果,如果 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

现在有关 constant pattern 您正在使用 (is 0) 的文档说:

When the input value is not an open type, the constant expression is implicitly converted to the type of the matched expression; if the type of the input value is not pattern-compatible with the type of the constant expression, the pattern-matching operation is an error.

正如我们发现的那样,开放类型(T[] 其中 T 未解析)泛型数组与 int 模式兼容,因此编译器可以处理您的表达式,而 string[](或任何其他封闭的通用数组)与模式不兼容并导致错误。

您可以查看第一个 link 的动机部分,了解他们为什么决定以这种方式更改规范。