Jérôme MEVEL
Jérôme MEVEL

Reputation: 7804

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

Upvotes: 9

Views: 1742

Answers (2)

canton7
canton7

Reputation: 42235

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;

Upvotes: 10

Joshua Robinson
Joshua Robinson

Reputation: 3539

Check out the specification on nullable reference types. It states that var infers an annotated type for reference types.

The part under the heading nullable implicitly typed local variables reads:

var infers an annotated type for reference types. For instance, in var s = ""; the var is inferred as string?.

Upvotes: 0

Related Questions