切换与var / null奇怪的行为

时间:2017-06-13 21:44:31

标签: c# null switch-statement var c#-7.0

给出以下代码:

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 var o

据我了解,case string ss == null时不匹配,因为(有效)(null as string) != null评估为false。 VS Code上的IntelliSense告诉我o也是string。有什么想法吗?

类似于:C# 7 switch case with null checks

3 个答案:

答案 0 :(得分:68)

在使用switch显式类型匹配case语句的模式中,询问所讨论的值是否属于该特定类型或派生类型。它与is

完全相同
switch (someString) {
  case string s:
}
if (someString is string) 

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

虽然模式匹配中的var类型充当外卡并且将匹配包括null在内的任何值。

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

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

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

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

答案 1 :(得分:22)

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

case string s:

被解释为if(someString is string) { s = (string)someString; ...if((s = (someString as string)) != null) { ... } - 其中任何一项涉及null测试 - 在您的情况下失败;相反地​​:

case var o:

编译器将o解析为string只是o = (string)someString; ... - 没有null测试,尽管它看起来类似于表面,只需使用提供类型的编译器。

最后:

default:

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

我同意这非常微妙而细致,令人困惑。但显然case var o场景使用了空传播(o?.Length ?? 0等)。我同意这很奇怪,var ostring s之间的非常不同,但它正是编译器目前所做的。

答案 2 :(得分:14)

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

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