Introduction
I use JetBrains Rider for my development and usually refactor my code as per the tips from Rider (or ReSharper if you are using Visual Studio). One of the tips that Rider suggests is to replace the traditional switch-case statements with a relatively new C# feature, switch expression. Here is the screenshot of the suggestion:

If you are a Visual Studio user, then Roslyn analyzer gives the same refactoring suggestion.

Most of the time, the refracting suggestion does not have any side-effect, and the code works as before.
Switch Expression refactoring may introduce a bug
Consider the below simple code:
Console.WriteLine("Is Null? " + (GetBoolean("Nah") == null));
enum Boolean
{
Yes,
No
}
static Boolean? GetBoolean(string boolString)
{
switch (boolString)
{
case "Yes":
return Boolean.Yes;
case "No":
return Boolean.No;
default:
return default;
}
}
The method GetBoolean
takes a string and returns a nullable enum. When the parameter boolString
does not match any case, it returns default
. That means when we pass parameter value as Nah
the method returns null
, and the output of the above code would be true
If we refactor the above code as per Rider or Visual Studio suggestion, the code would look as below:
static Boolean? GetBoolean(string boolString)
{
return boolString switch
{
"Yes" => Boolean.Yes,
"No" => Boolean.No,
_ => default
};
}
At first glance, the above code appears correct, and we would expect it to return null
when we pass the parameter value as Nah
as in the previous code snippet.
However, the method returns Yes
instead. And the output of the code changes to false
Why does this happen?
I landed into this issue very recently, and luckily, a failed test helped me discover this bug. I raised this question on Twitter
The reason we see this behaviour is because, with switch expression, the first “case” does not return a Boolean?
but Boolean
instead. As a result, it infers the default
as a default Boolean
which is Yes
leading to this bug.
@citizenmatt (Matt Ellis) sumps it up pretty nicely in his tweet
Matt Ellis (from JetBrains) and David Kean (from Visual Studio) were kind enough to raise a bug to fix this in the future release.
fixing the switch expression
To fix this issue, we can typecast the first case of switch expression as Boolean?
.
static Boolean? GetBoolean(string boolString)
{
return boolString switch
{
"Yes" => (Boolean?)Boolean.Yes,
"No" => Boolean.No,
_ => default
};
}
Alternatively, we can return the default as null
instead.
static Boolean? GetBoolean(string boolString)
{
return boolString switch
{
"Yes" => Boolean.Yes,
"No" => Boolean.No,
_ => null
};
}
Personally, I went for the second approach as I find it cleaner.
Wrapping Up
This whole exercise was a great learning exercise for me. It shows that we need to be careful when dealing with default
type in C# especially when using it with switch expression. Hope you also find this useful.
Leave a Reply