C# 为什么字符串常量上的switch case语句在Visual Studio 2019(16.0.3之前)中需要默认值,而在Visual Studio 2017中则不需要?

C# 为什么字符串常量上的switch case语句在Visual Studio 2019(16.0.3之前)中需要默认值,而在Visual Studio 2017中则不需要?,c#,visual-studio-2019,C#,Visual Studio 2019,我正在Visual Studio 2017中编写的代码库上试用Visual Studio 2019,并立即发现构建问题。我有一个开关case语句,其中case是在常量字符串上选择的。这没有默认情况,在Visual Studio 2017中可以,但在Visual Studio 2019中会抛出生成错误 我可以通过添加一个默认案例来解决这个问题,但我希望避免代码更改,如果可能的话,只需更改编译器设置,以避免需要拉请求。无论如何,最好了解问题的原因 public class Program {

我正在Visual Studio 2017中编写的代码库上试用Visual Studio 2019,并立即发现构建问题。我有一个
开关case
语句,其中case是在常量字符串上选择的。这没有默认情况,在Visual Studio 2017中可以,但在Visual Studio 2019中会抛出生成错误

我可以通过添加一个默认案例来解决这个问题,但我希望避免代码更改,如果可能的话,只需更改编译器设置,以避免需要拉请求。无论如何,最好了解问题的原因

public class Program
{
    public const string Database = "MongoDB";

    public static string GetDb()
    {
        switch (Database)
        {
            case "MongoDB":
                return Database;
        }
    }
}
包含示例解决方案的github存储库可以在以下位置找到: 这包括示例解决方案在添加到github之前的状态下的存档

在Visual Studio 2017中,生成的输出为:

1>------ Rebuild All started: Project: NoDefaultCase, Configuration: Debug Any CPU ------
1>  NoDefaultCase -> C:\Users\MartinEyles\source\repos\NoDefaultCase\NoDefaultCase\bin\Debug\NoDefaultCase.exe
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========
1>------ Rebuild All started: Project: NoDefaultCase, Configuration: Debug Any CPU ------
1>C:\Users\MartinEyles\source\repos\NoDefaultCase\NoDefaultCase\Program.cs(9,30,9,35): error CS0161: 'Program.GetDb()': not all code paths return a value
========== Rebuild All: 0 succeeded, 1 failed, 0 skipped ==========
在Visual Studio 2019中,生成的输出为:

1>------ Rebuild All started: Project: NoDefaultCase, Configuration: Debug Any CPU ------
1>  NoDefaultCase -> C:\Users\MartinEyles\source\repos\NoDefaultCase\NoDefaultCase\bin\Debug\NoDefaultCase.exe
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========
1>------ Rebuild All started: Project: NoDefaultCase, Configuration: Debug Any CPU ------
1>C:\Users\MartinEyles\source\repos\NoDefaultCase\NoDefaultCase\Program.cs(9,30,9,35): error CS0161: 'Program.GetDb()': not all code paths return a value
========== Rebuild All: 0 succeeded, 1 failed, 0 skipped ==========
我的目标是.NETFramework 4.7.2和默认语言版本。我还尝试将语言版本降低到C#6.0,并手动将语言版本设置为C#7.3,结果相同

我正在使用的Visual Studio的特定版本有:

Microsoft Visual Studio Enterprise 2017 
Version 15.9.11
VisualStudio.15.Release/15.9.11+28307.586
Microsoft .NET Framework Version 4.7.03056

该问题通过以下方式解决:

Microsoft Visual Studio Enterprise 2019
Version 16.0.3
VisualStudio.16.Release/16.0.3+28803.352
Microsoft .NET Framework Version 4.7.03056
在C#6中,匹配表达式必须是返回 以下类型的值:

字符。
一串<布尔值。
整型值,
如整型或长型。
枚举值。
从C#7.0开始,匹配表达式可以是任何 非空表达式。

文档中说,使用c#7.0,匹配表达式可以是任何非空表达式。 在c#7中,字符串变成了可为null的类型,因此必须添加默认情况(对于null情况)

看起来规范将使用新的可达性规则进行更新,或者这是Roslyn中的一个错误,可能是由于开关表达式引入的更改

对于编译器来说,重要的问题是方法的结尾是否是可访问的——当且仅当switch语句的结尾是可访问的时,方法的结尾才是可访问的

第13.8.3节描述了切换语句结尾的可达性:

如果至少满足以下条件之一,则可以访问switch语句的端点:

  • switch语句包含退出switch语句的可到达中断语句
  • switch语句是可访问的,switch表达式是非常量值,并且不存在默认标签
  • switch语句是可访问的,switch表达式是不匹配任何大小写标签的常量值,并且不存在默认标签
在您的示例中,似乎没有一个是这样的:

  • 没有中断语句
  • 开关表达式是一个常量值
  • 常量值与案例标签不匹配

因此,使用C#5规则,这个switch语句的端点是不可到达的,它应该可以顺利编译。具有相同的文本,因此看起来还没有更改…

它是给您生成错误还是生成警告?默认情况不应该是必需的。它在2019年为我编译,C#语言版本设置为7.3(如果我用其他东西替换MongoDatabase),好吧,你是对的。该问题确实发生在VS2019的非预览版本中。你应该向微软提出。同时,考虑使用VS 2019中的C 8β编译器——它没有出现问题。这也被记录在:但是我不确定这是一个bug还是一个需要改变的设置,所以我仍然认为它在此刻是有关联的。似乎固定在16.0.3。但它在Visual Studio 2017中仍然可以很好地编译。借助Visual Studio 2019的新功能:开关表达式必须始终返回值。但是,即使不是这样,代码仍将编译(即,案例未涵盖所有可能的值),编译器将仅对上述代码发出警告。如果在运行时测试值与任何情况都不匹配,则将抛出InvalidOperationException。我收到的是生成错误,而不是警告。CS0161 C#'':并非所有代码路径都返回值我已尝试在新项目中提取相关代码,并将project advanced build properties中的C#language版本设置为6.0,但在Visual Studio 2019中仍然无法编译,并出现相同的生成错误,并继续在visual studio 2017中成功构建。
开关表达式必须始终返回值。
此代码不包含开关表达式。它在C#8(beta版)中编译的事实表明这是一个错误。我想我们很快就会找到办法的!Roslyn团队已经确认这是一个bug。这个问题在他们的GitHub页面上被提到:这表明这个问题在这个版本中得到了解决,我可以确认示例代码是在16.0.3中构建的。