I've found a strange inconsistency between the nullability of a variable in the hover-over tooltip in Visual Studio / sharplab.io and the compiler's handling of the variable re nullability.
I wanted to check if I'm missing something or if this is maybe a bug...
Live link: sharplab.io
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
public sealed class RectangleInfo
{
}
public sealed class PreviewLayout
{
public sealed class Builder
{
public Builder()
{
this.Screens = new();
}
public List<RectangleInfo> Screens
{
get;
set;
}
public PreviewLayout Build()
{
return new PreviewLayout();
}
}
}
public static class LayoutHelper
{
public static PreviewLayout GetPreviewLayout()
{
var builder = new PreviewLayout.Builder();
var screen = builder.Screens.Single();
Console.WriteLine(screen.GetType().FullName);
return builder.Build();
}
}
If you hover the mouse over the screen
in var screen = builder.Screens.Single();
you'll see this tooltip:
(local variable) RectangleInfo? screen
(note that RectangleInfo?
is nullable, which is strange because Single()
definitely returns a RectangleInfo
in this case and there's no other nullability warnings / errors)
but in the next line screen
is being treated as "not null" because this gives no Dereference of a possibly null reference.
warning:
screen.GetType().FullName
If you replace var
in var screen = ...
with RectangleInfo
the tooltip reports:
(local variable) RectangleInfo? screen
I get the same behaviour in Visual Studio, so presumably this is something the C# compiler / Roslyn is doing.
Have I missed something that means screen
should legitimately be a nullable RectangleInfo?
?
When you use
var
in the enabled nullable aware context and the type of an initialization expression is a reference type, the compiler always infers a nullable reference type even if the type of an initialization expression isn't nullable.
Suppose you did this:
var screen = builder.Screens.Single();
if(...something...)
{
screen = null;
}
The C# designers determined you wouldn't want the compiler to warn you about screen = null
because you never really said it had to be not-null in the first place. Fortunately, just because the variable is declared as nullable doesn't mean that it has to warn you about dereferencing: you could do this and it would work just fine, because the compiler knows that screen
is not null in context:
Screen? screen = builder.Screens.Single();
Console.WriteLine(screen.GetType().FullName);