Consider the following code:
using System;
#nullable enable
namespace Demo
{
public sealed class TestClass
{
public string Test()
{
bool isNull = _test == null;
if (isNull)
return "";
else
return _test; // !!!
}
readonly string _test = "";
}
}
When I build this, the line marked with !!!
gives a compiler warning: warning CS8603: Possible null reference return.
.
I find this a little confusing, given that _test
is readonly and initialised to non-null.
If I change the code to the following, the warning goes away:
public string Test()
{
// bool isNull = _test == null;
if (_test == null)
return "";
else
return _test;
}
Can anyone explain this behaviour?
The nullable flow analysis tracks the null state of variables, but it does not track other state, such as the value of a bool
variable (as isNull
above), and it does not track the relationship between the state of separate variables (e.g. isNull
and _test
).
An actual static analysis engine would probably do those things, but would also be "heuristic" or "arbitrary" to some degree: you couldn't necessarily tell the rules it was following, and those rules might even change over time.
That's not something we can do directly in the C# compiler. The rules for nullable warnings are quite sophisticated (as Jon's analysis shows!), but they are rules, and can be reasoned about.
As we roll out the feature it feels like we mostly struck the right balance, but there are a few places that do come up as awkward, and we'll be revisiting those for C# 9.0.