C# switch expression incorrect nullability

Viewed 400

I notice when using a switch expression which includes a null check as the range expression, the nullability state of the value in arms/cases isn't interpreted correctly in Visual Studio (16.7.6). For example:

string? value = GetSomeString();
var description = (value != null) switch
{
    true when value.Length == 0 => "Empty",
    true when value.Length == 1 => "Uno",
    true when value.Length == 3 => "Third time's a charm",
    _ => "null"
};

Here I expect to know within the switch block that all instances of value are not null, given the condition we're switching on. The last/default case handles the null case. Yet, Visual Studio thinks the first instance might be null:

enter image description here

Am I doing something wrong, is this a bug with the analyzer, or otherwise?

2 Answers

You're switching on this condition: (value != null), which evaluate to true or false. Still, the variable value itself can still be null when inside the switch expression, so that hint is actually correct. Whenever the result of (value != null) is false, you'll still enter the switch body, and value will be null. In summary, the switch body will be executed regardless of whether value is null or not.

EDIT:

Scratch that, I got it wrong, you're right. value will not be null inside the specific conditions, though it might be null in the switch body. There's something funny with your Visual Studio, this is what I get (I'm using VS 16.4.5), no warnings:

enter image description here

I think that in your simple example we could all agree that once checked for null value will continue to retain that value, however neither the compiler or the runtime can make that guarantee.

It is fairly trivial to write another example in which the value of value could be set to null between the time that (value != null) is evaluated and any of the true when value.Length ... statements are.

Thus making the warning, 'value' may be null here, valid.

string? value = default;

Parallel.For(0, 4, _ =>
{
    while (true)
    {
        value = "Has a value";

        var description = (value != null) switch
        {
            true when value.Length == 0 => "Empty",
            true when value.Length == 1 => "Uno",
            true when value.Length == 3 => "Thrid time's a charm",
            _ => "null"
        };

        value = null; 
    }
});

enter image description here

Alternative ways to write such an expression would be

when value?.Length == 0 => "Empty",
when value?.Length == 1 => "Uno",
when value?.Length == 3 => "Thrid time's a charm",

or

var description = value?.Length switch
{
    0 => "Empty",
    1 => "Uno",
    3 => "Thrid time's a charm",
    _ => "null"
};
Related