当前位置: 首页 > 知识库问答 >
问题:

具有var/null奇怪行为的开关

司徒云
2023-03-14

鉴于以下代码:

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上匹配?

我的理解是,当s==null时,大小写字符串s不匹配,因为(实际上)(null为字符串)!=null计算结果为false。VS Code上的IntelliSense告诉我,o也是一个字符串。有什么想法吗?

类似于:带有空检查的C#7开关外壳


共有3个答案

公孙辰龙
2023-03-14

这是因为case

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

皮安顺
2023-03-14

我在这里整理了多条twitter评论——这对我来说确实是新鲜事,我希望jaredpar能给出一个更全面的答案,但是;据我所知的简短版本:

case string s:

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

case var o:

其中,编译器将o解析string就是o=(string)someString-nonulltest,尽管它在表面上看起来很相似,只是编译器提供了类型。

最后:

default:

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

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

谭奕
2023-03-14
匿名用户

在模式匹配switch语句中,对显式类型使用case询问所讨论的值是该特定类型还是派生类型。它完全等同于is

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

null没有类型,因此不满足上述任一条件。在这两个例子中,someString的静态类型都不起作用。

模式匹配中的var类型虽然起着通配符的作用,它将匹配任何值,包括null

这里的默认情况是死代码。case var o将匹配任何值,无论是空值还是非空值。非默认案例总是胜过默认案例,因此default永远不会被击中。如果你看一下IL,你会发现它甚至没有被释放出来。

乍一看,这似乎很奇怪,它在没有任何警告的情况下编译(绝对让我大吃一惊)。但是这与可以追溯到1.0的C#行为相匹配。编译器允许默认情况,即使它可以简单地证明它永远不会被命中。以下面为例:

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

在这里,default将永远不会被命中(即使对于值不是1或0的bool)。然而,C#从1.0开始就在没有警告的情况下允许这样做。模式匹配正符合这种行为。

 类似资料:
  • 问题内容: 我在JTextPane / JTextField(或它们下方的字体渲染中的某个地方)中发现了一个奇怪的错误。我想知道是否有人遇到过这种情况,并且可能对此有解决方案。 我试图在JTextPane中显示一些“特殊”或稀有字符,并且一旦更改JTextField的字体(与JTextPane完全无关!),JTextPane就会“分手”,不再显示这些字符字符。 这应该可以更好地解释我的意思: 编辑

  • 我有以下代码来解析一个JSON文件: 要处理以下JSON文件: 如果我执行此代码,我将收到以下错误: 所以我开始一步一步地调试应用程序,看看part processing()中的哪个代码部分抛出了这个异常。令人惊讶的是,那里的所有代码都正常执行:没有抛出异常,也没有返回结果I except。 更让我惊讶的是,当我稍微改变第一种方法的代码时,它可以在不产生异常的情况下工作。 我不知道println方

  • 问题内容: 我看到了我认为是错误的行为。@InjectMocks似乎并没有在每种测试方法之前创建一个新的测试主题。就像@Mock一样。在下面的示例中,如果Subject.section是最后一个,则@Test失败。如果不是最后两个都通过。我当前的解决方法是使用@BeforeClass,但这并不理想。 Subject.java: Section.java: SubjectTest.java 干杯。

  • 问题内容: 我在GregorianCalendar类中遇到一个奇怪的行为,我想知道我是否真的做得不好。 仅当初始化日期的月份的实际Maximum大于我将日历设置为的月份时,才追加此值。 这是示例代码: 我知道问题是由于日历初始化日期是31天(可能是5月),与设置为2月(28天)的月份混淆了。修复很容易(只需在设置年和月之前将day_of_month设置为1),但是我想知道这确实是想要的行为。有什么

  • 问题内容: 我正在为一个问题而苦苦挣扎,我不明白为什么它不起作用。如何通过将变量传递并转换为? 为什么在顶部代码段中不起作用,但在行下方的底部代码段中起作用? 唯一的区别似乎是添加了一个额外的变量,该变量也被键入为? 问题答案: 该是一种原始类型,同时是一个普通的Java类。您不能在原始类型上调用方法。但是该方法在上可用,如javadoc中所示 有关这些原始类型的更多信息,请参见此处

  • 问题内容: 为什么的到哪里去了? 问题答案: 删除任何字符,并从字符串的开头和结尾。