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

Mar*_*les 11 c# visual-studio-2019

我正在使用Visual Studio 2017编写的代码基础上试用Visual Studio 2019,并立即发现生成问题。我有一个switch 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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

可以在https://github.com/martineyles/NoDefaultCase上找到包含示例解决方案的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 ==========
Run Code Online (Sandbox Code Playgroud)

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

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 ==========
Run Code Online (Sandbox Code Playgroud)

我的目标是.net Framework 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
Run Code Online (Sandbox Code Playgroud)

Microsoft Visual Studio Enterprise 2019 
Version 16.0.0
VisualStudio.16.Release/16.0.0+28729.10
Microsoft .NET Framework Version 4.7.03056
Run Code Online (Sandbox Code Playgroud)

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

Microsoft Visual Studio Enterprise 2019
Version 16.0.3
VisualStudio.16.Release/16.0.3+28803.352
Microsoft .NET Framework Version 4.7.03056
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 8

它看起来像任何规格将与新规则的可达性进行更新,或者这是罗斯林的错误,可能是由于与开关表达式引入的更改。

对于编译器而言,重要的问题是方法的末尾是否可以到达-当且仅当switch语句的末尾可以到达时才是。

ECMA C#5标准部分13.8.3描述了一种开关语句结束的可达性:

如果满足以下至少一项,则将达到switch语句的终点:

  • switch语句包含一个可到达的break语句,该语句退出switch语句。
  • switch语句是可到达的,switch表达式是一个非恒定值,并且没有默认标签。
  • switch语句是可到达的,switch表达式是一个不与任何case标签匹配的常量值,并且不存在默认标签。

在您的示例中,似乎没有这些情况:

  • 没有中断声明
  • 开关表达式是一个常数值
  • 恒定值匹配的情况下,标签

因此,使用C#5规则,此switch语句的终点是可达的,并且应该可以毫无问题地进行编译。将在GitHub的规范草案的文字相同,所以它看起来并不像它的改变,因此尚未...

  • 罗斯林团队已确认这是一个错误。该问题在其GitHub页面上提及:https://github.com/dotnet/roslyn/issues/35011 (2认同)