Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Non-nullable reference type: why is my object considered nullable by the compiler?

I've a project on which I enabled the new Nullable reference type feature

 <Nullable>enable</Nullable>

Now let's consider this code

public class Foo  {    }

var foo = new Foo();

The compiler considers the foo variable to be nullable (Foo?). Why is that? I don't understand.

Now with the Nullable reference type feature enabled the returned Foo object isn't supposed to be null because it is a non-nullable type.

If I wanted it to be nullable I'd specify it has a Foo?

So why is the compiler saying it's a nullable variable?

Thank you

EDIT

Here is a screenshot of what I'm describing here. When you hover your mouse over the foo variable

Hover the foo variable

like image 758
Jérôme MEVEL Avatar asked Jun 19 '20 15:06

Jérôme MEVEL


1 Answers

In the original implementation, foo would have been inferred as a Foo.

However, people complained that this got in the way of things like:

string? GetThing() => ...

var result = "";
if (condition)
{
    result = GetThing();
}

If result is inferred as a string, then the result = GetThing() line causes a warning: GetThing() returns a string?, and there's a warning if you try and assign a string? to a string.

The solution was to infer result as a string?, but the compiler knows that it's currently not null (its "flow state" is "NotNull").

This means that:

string? GetThing() => ...

var result = "";

// No warning, as the compiler knows that result isn't null
int l1 = result.Length; 

if (condition)
{
    result = GetThing();
}

// Warning: the compiler knows 'result' might have been re-assigned
int l2 = result.Length; 

For other examples of the flow state at work, see things like:

string? result = GetString();
if (result == null)
    throw new Exception();

// No warning: the compiler knows that result can't be null here: if it was,
// the exception above would have been thrown
int l1 = result.Length;
string? result = GetString();

// Warning: result might be null
int l1 = result.Length; 

// No warning: the compiler knows that result can't be null here: if it was,
// the line above would have thrown
int l2 = result.Length; 
string result = "hello";
if (result == null)
    Console.WriteLine("NULL!");

// Warning: because we checked for null above, the compiler assumes that we
// know something that it doesn't, and so result might be null.
int l1 = result.Length;
like image 50
canton7 Avatar answered Oct 03 '22 19:10

canton7