切换 var/null 奇怪的行为
switch with var/null strange behavior
给定以下代码:
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 s
在 s == null
时不匹配,因为(实际上)(null as string) != null
的计算结果为 false。 VS Code 上的 IntelliSense 告诉我 o
也是 string
。有什么想法吗?
类似于:C# 7 switch case with null checks
我在这里汇总了多条 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 o
和 string s
之间如此 非常 不同是很奇怪的,但这是编译器当前所做的。
在模式匹配 switch
语句中使用 case
作为显式类型是在询问所讨论的值是该特定类型还是派生类型。它完全等同于 is
switch (someString) {
case string s:
}
if (someString is string)
值 null
没有类型,因此不满足上述任一条件。 someString
的静态类型在这两个示例中都没有发挥作用。
虽然在模式匹配中 var
类型充当通配符,但会匹配包括 null
在内的任何值。
这里的default
案例是死代码。 case var o
将匹配任何值,空值或非空值。非默认情况总是胜过默认情况,因此 default
永远不会被击中。如果您查看 IL,您会发现它甚至没有发出。
乍一看,编译没有任何警告似乎很奇怪(绝对让我失望)。但这与可追溯到 1.0 的 C# 行为相匹配。编译器允许 default
个案例,即使它可以简单地证明它永远不会被击中。考虑以下示例:
bool b = ...;
switch (b) {
case true: ...
case false: ...
default: ...
}
这里 default
永远不会被命中(即使 bool
的值不是 1 或 0)。然而 C# 从 1.0 开始就在没有警告的情况下允许这样做。模式匹配只是符合这里的这种行为。
这是因为 case <Type>
匹配 dynamic(运行-time)类型,而不是静态(编译时)类型。 null
没有动态类型,因此无法与 string
匹配。 var
只是备用。
(发帖是因为我喜欢简短的回答。)
给定以下代码:
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 s
在 s == null
时不匹配,因为(实际上)(null as string) != null
的计算结果为 false。 VS Code 上的 IntelliSense 告诉我 o
也是 string
。有什么想法吗?
类似于:C# 7 switch case with null checks
我在这里汇总了多条 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 o
和 string s
之间如此 非常 不同是很奇怪的,但这是编译器当前所做的。
在模式匹配 switch
语句中使用 case
作为显式类型是在询问所讨论的值是该特定类型还是派生类型。它完全等同于 is
switch (someString) {
case string s:
}
if (someString is string)
值 null
没有类型,因此不满足上述任一条件。 someString
的静态类型在这两个示例中都没有发挥作用。
虽然在模式匹配中 var
类型充当通配符,但会匹配包括 null
在内的任何值。
这里的default
案例是死代码。 case var o
将匹配任何值,空值或非空值。非默认情况总是胜过默认情况,因此 default
永远不会被击中。如果您查看 IL,您会发现它甚至没有发出。
乍一看,编译没有任何警告似乎很奇怪(绝对让我失望)。但这与可追溯到 1.0 的 C# 行为相匹配。编译器允许 default
个案例,即使它可以简单地证明它永远不会被击中。考虑以下示例:
bool b = ...;
switch (b) {
case true: ...
case false: ...
default: ...
}
这里 default
永远不会被命中(即使 bool
的值不是 1 或 0)。然而 C# 从 1.0 开始就在没有警告的情况下允许这样做。模式匹配只是符合这里的这种行为。
这是因为 case <Type>
匹配 dynamic(运行-time)类型,而不是静态(编译时)类型。 null
没有动态类型,因此无法与 string
匹配。 var
只是备用。
(发帖是因为我喜欢简短的回答。)