c# - 用var / null奇怪行为切换

给出以下代码:

string someString = null;
switch (someString)
{
    case string s:
        Console.WriteLine("string s");
        break;
    case var o:
        Console.WriteLine("var o");
        break;
    default:
        Console.WriteLine("default");
        break;
}

为什么switch语句匹配case string s

据我所知,case string ss == null不匹配,因为(有效)(null as string) != null的评估结果为false。 VS Code上的智能感知告诉我o也是string。 有什么想法吗?


类似于:C#7切换案例,带有空检查

budi asked 2019-08-27T17:35:24Z
3个解决方案
68 votes

对于显式类型,使用default匹配switch语句的模式内部,询问所讨论的值是否属于该特定类型或派生类型。 它完全相同于bool

switch (someString) {
  case string s:
}
if (someString is string) 

default没有类型,因此不满足上述任一条件。 在任何一个例子中,静态类型bool都没有发挥作用。

模式匹配中的default类型充当外卡并且将匹配包括bool在内的任何值。

这里的default案例是死代码。 bool将匹配任何值,null或非null。 非默认情况总是胜过默认情况,因此default永远不会被击中。 如果你看IL,你会发现它甚至没有被发射出来。

一目了然,这可能看起来很奇怪,这个编译没有任何警告(肯定会让我离开)。 但这与C#行为相匹配,可以追溯到1.0。 编译器允许default个案例,即使它可以简单地证明它永远不会被命中。 以下面的例子为例:

bool b = ...;
switch (b) {
  case true: ...
  case false: ...
  default: ...
}

这里default永远不会被击中(即使是bool,其值不是1或0)。 然而,C#在没有任何警告的情况下允许1.0。 模式匹配正好符合这种行为。

JaredPar answered 2019-08-27T17:36:15Z
22 votes

我在这里汇集了多个Twitter评论 - 这对我来说实际上是新的,我希望jaredpar能够提供更全面的答案,但是; 我理解的简短版本:

case string s:

被解释为case var oo?.Length ?? 0 - 其中任何一个涉及var o测试 - 在您的情况下失败; 反过来:

case var o:

其中编译器解析case var oo?.Length ?? 0只是var o - 没有string s测试,尽管表面看起来很相似,只是提供了类型的编译器。

最后:

default:

这里无法到达,因为上面的案例抓住了一切。 这可能是一个编译器错误,因为它没有发出无法访问的代码警告。

我同意这是非常微妙和细微的,令人困惑的。 但显然case var o场景具有空传播的用途(o?.Length ?? 0等)。 我同意在var ostring s之间的工作方式非常不同,这很奇怪,但它是编译器目前所做的。

Marc Gravell answered 2019-08-27T17:37:19Z
14 votes

这是因为case <Type>匹配动态(运行时)类型,而不是静态(编译时)类型。 null没有动态类型,因此无法与string匹配.var只是后备。

(发帖因为我喜欢简短的答案。)

Mehrdad answered 2019-08-27T17:37:55Z
translate from https://stackoverflow.com:/questions/44532077/switch-with-var-null-strange-behavior