Strange behaviour of nullable references checking #3433
-
Given a class
Why is there no any warning in the last line? But the warning appears when the previous line is uncommented. Looks like a bug. |
Beta Was this translation helpful? Give feedback.
Replies: 10 comments
-
As an aside, bugs in null flow analysis should be opened in the roslyn repository. However this behaviour, whilst surprising, is as expected. Linq hasn't been annotated yet, so the compiler doesn't know first can be null. It assumes that the value returned from However, when do an explicit check for null, by calling |
Beta Was this translation helpful? Give feedback.
-
Yeah, thank you, I've understood. The compiler is sure that FirstOrDefault always returns non-null. And even when I declare a variable as nullable, it doesn't believe that null is possible until I check it explicitly. |
Beta Was this translation helpful? Give feedback.
-
That is also expected. When you check a variable for |
Beta Was this translation helpful? Give feedback.
-
Yeah, but why wouldn't compiler make the same conclusion at the first line due to nullable variable declaration? |
Beta Was this translation helpful? Give feedback.
-
Because there's other reasons you might declare a variable nullable. E.g. SomeClass? M()
{
SomeClass? result = GetSomeClass(); //returns nonnullable instance of SomeClass;
Log(result.ToString()); //doesn't warn since we know result is not null here.
if (result.IsInvalid)
result = null; // no warning since variable is nullable
return result;
} You have to distinguish between the flow state of a variable at any point in the code, which says "can this be null right now?", and the type of a variable, which specifies which values you are allowed to put in it. |
Beta Was this translation helpful? Give feedback.
-
Yes I do, but my question is why can't the flow rely on the type declared by user instead of a doubtful comparison somewhere in the code? |
Beta Was this translation helpful? Give feedback.
-
So that examples like Yair posted are possible. |
Beta Was this translation helpful? Give feedback.
-
In fact in that example we don't know what GetSomeClass() returns. Maybe it's like FirstOfDefault() - can be null but isn't marked yet. And compiler ignores our tip ( |
Beta Was this translation helpful? Give feedback.
-
Consider a case where it's in nullable aware code, and is annotated as not returning null: #nullable enable
SomeClass? M()
{
SomeClass? result = GetSomeClass(); //returns nonnullable instance of SomeClass;
Log(result.ToString()); //doesn't warn since we know result is not null here.
if (result.IsInvalid)
result = null; // no warning since variable is nullable
return result;
}
SomeClass GetSomeClass() => new SomeClass(); |
Beta Was this translation helpful? Give feedback.
-
I see the logic, thank you. I keep in mind Kotlin as a reference, but in C# the same is impossible unfortunately due backward compatibility. |
Beta Was this translation helpful? Give feedback.
As an aside, bugs in null flow analysis should be opened in the roslyn repository.
However this behaviour, whilst surprising, is as expected.
Linq hasn't been annotated yet, so the compiler doesn't know first can be null. It assumes that the value returned from
FirstOrDefault
is not null. Specifying the type asobject?
doesn't change this - that only allows you to assign null to that local, but doesn't affect its flow state. Therefore it doesn't warn onfirst.GetType()
.However, when do an explicit check for null, by calling
if(first == null)
, the compiler assumes that you are telling it that first can be null. Therefore it warns when you later callfirst.GetType()