Consider the following code:
using System;
#nullable enable
namespace Demo
{
public sealed class TestClass
{
public string Test()
{
You have discovered evidence that the program-flow algorithm that produces this warning is relatively unsophisticated when it comes to tracking the meanings encoded in local variables.
I have no specific knowledge of the flow checker's implementation, but having worked on implementations of similar code in the past, I can make some educated guesses. The flow checker is likely deducing two things in the false positive case: (1) _test
could be null, because if it could not, you would not have the comparison in the first place, and (2) isNull
could be true or false -- because if it could not, you would not have it in an if
. But the connection that the return _test;
only runs if _test
is not null, that connection is not being made.
This is a surprisingly tricky problem, and you should expect that it will take a while for the compiler to attain the sophistication of tools that have had multiple years of work by experts. The Coverity flow checker, for example, would have no problem at all in deducing that neither of your two variations had a null return, but the Coverity flow checker costs serious money for corporate customers.
Also, the Coverity checkers are designed to run on large codebases overnight; the C# compiler's analysis must run between keystrokes in the editor, which significantly changes the sorts of in-depth analyses you can reasonably perform.