用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; }
为什么在case var o
上匹配switch语句?
这是我的理解, case string s
不匹配时, s == null
因为(有效) (null as string) != null
计算结果为false。 对VS Code的智能感知告诉我, o
也是一个string
。 有什么想法吗?
熟悉到: C#7切换案件与空检查
在一个模式匹配的switch
语句中使用一个显式types的情况是询问有问题的值是否是特定的types或派生types。 这是确切的等值
switch (someString) { case string s: } if (someString is string)
null
不具有types,因此不符合上述任一条件。 someString
的静态types在任何一个例子中都不起作用。
虽然在模式匹配中的var
types作为通配符,并将匹配任何值,包括null
。
这里的default
情况是死代码。 case var o
将匹配任何值,null或非null。 非默认情况下总是赢得一个默认值,因此default
永远不会被触发。 如果你看看IL,你会发现它甚至没有发射。
一眼看来,这个编译没有任何警告似乎很奇怪(肯定把我扔了)。 但是这与C#行为可以追溯到1.0。 编译器允许default
情况下,即使它可以平凡地certificate它将永远不会被击中。 考虑一个例子如下:
bool b = ...; switch (b) { case true: ... case false: ... default: ... }
这里default
不会被命中的(即使对于bool
值不是1或0)。 然而,C#已经允许1.0以来没有警告。 模式匹配正好符合这种行为。
我在这里把多个Twitter的评论放在一起 – 这对我来说实际上是新的,我希望jaredpar将跳出一个更全面的答案,但是; 短版本,据我所知:
case string s:
被解释为if(someString is string) { s = (string)someString; ...
if(someString is string) { s = (string)someString; ...
或者if((s = (someString as string)) != null) { ... }
– 其中任何一个涉及null
testing – 在你的情况下失败; 反过来:
case var o:
编译器将string
parsing为o
就是o = (string)someString; ...
o = (string)someString; ...
– 没有null
testing, 尽pipe表面上看起来很相似,只是编译器提供了types。
最后:
default:
在这里无法达成 ,因为上面的情况捕捉到了一切。 这可能是一个编译器错误,因为它没有发出不可达的代码警告。
我同意这是非常微妙和微妙的,令人困惑。 但显然case var o
情况已经使用null传播( o?.Length ?? 0
等)。 我同意奇怪的是, var o
和string s
之间的工作方式非常不同,但编译器目前所做的是。
这是因为case <Type>
匹配dynamic (运行时)types,而不是静态(编译时)types。 null
没有dynamictypes,所以它不能匹配string
。 var
只是后备。
(发布,因为我喜欢简短的答案。)