简体   繁体   中英

Why does a switch-case statement on a string constant require a default in Visual Studio 2019 (prior to 16.0.3) but not in Visual Studio 2017?

I am trying out Visual Studio 2019 on a code base written in Visual Studio 2017, and am immediately finding a build issue. I have a switch case statement in which the case is selected on a constant string. This doesn't have a default case, which is fine in Visual Studio 2017, but throws a build error in Visual Studio 2019.

I can resolve the issue by adding a default case, but I would like to avoid a code change and just change a compiler setting if possible, to avoid the need for a pull request. In any case it would be good to understand the reason for the issue.

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

    public static string GetDb()
    {
        switch (Database)
        {
            case "MongoDB":
                return Database;
        }
    }
}

A github repository containing the example solution can be found at https://github.com/martineyles/NoDefaultCase This includes an archive of the example solution in the state before it was added to github.

In Visual Studio 2017, the output of the build is:

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 ==========

In Visual Studio 2019, the output of the build is:

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 ==========

I am targeting .net framework 4.7.2 and the default language version. I have also tried reducing the language version to C# 6.0 and setting the language version manually to C# 7.3 with the same results.

The specific version of Visual Studio I am using are:

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

and

Microsoft Visual Studio Enterprise 2019 
Version 16.0.0
VisualStudio.16.Release/16.0.0+28729.10
Microsoft .NET Framework Version 4.7.03056

The issue is resolved in:

Microsoft Visual Studio Enterprise 2019
Version 16.0.3
VisualStudio.16.Release/16.0.3+28803.352
Microsoft .NET Framework Version 4.7.03056

It looks like either the specification will be updated with new rules on reachability, or this is a bug in Roslyn, probably due to changes introduced with switch expressions.

The important question for the compiler is whether the end of the method is reachable - which it will be if and only if the end of the switch statement is reachable.

The ECMA C# 5 standard section 13.8.3 describes the reachability of the end of a switch statement:

The end point of a switch statement is reachable if at least one of the following is true:

  • The switch statement contains a reachable break statement that exits the switch statement.
  • The switch statement is reachable, the switch expression is a non-constant value, and no default label is present.
  • The switch statement is reachable, the switch expression is a constant value that doesn't match any case label, and no default label is present.

None of these seem to be the case in your example:

  • There are no break statements
  • The switch expression is a constant value
  • The constant value does match a case label

So with C# 5 rules, the end point of this switch statement is not reachable, and it should compile with no problems. The draft specification in GitHub has the same text, so it doesn't look like it's changed there yet...

In C# 6, the match expression must be an expression that returns a value of the following types:

a char.
a string.
a bool.
an integral value,
such as an int or a long.
an enum value.
Starting with C# 7.0, the match expression can be any non-null expression.

the documentation said that with c# 7.0 the match expression can be any non-null expression. in c# 7 , string become a nullable type so you must add the default case ( for the null case )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM