I am experiencing an issue with Visual Studio 2022 (C# .NET 6.0) where it is giving a CS8602 warning ("Dereference of a possibly null reference") even after a null check is performed. Here is the code snippet:
public interface IParameter
{
public string? Input { get; set; }
}
public static class FalseWarningTest
{
public static string[] SeeTheFalseWarning(this IParameter parameter)
{
if (string.IsNullOrWhiteSpace(parameter.Input))
{
throw new InvalidOperationException("Input must have value");
}
return parameter.Input.Split(':');
}
}
Despite the check for null or whitespace on parameter.Input
before it is used, Visual Studio is still warning that it could be possibly null at the point where it’s used.
However, when I explicitly check for null (which should be redundant), the warning disappears:
public static string[] SeeTheFalseWarning(this IParameter parameter)
{
if (parameter.Input == null || string.IsNullOrWhiteSpace(parameter.Input))
{
throw new InvalidOperationException("Input must have value");
}
return parameter.Input.Split(':');
}
I understand that the CS8602 warning is a feature to prevent null reference exceptions. But, Is this a bug in this case since the null and whitespace checks are performed before using parameter.Input
, or am I misunderstanding something?
Edit #1:
Setting the local variable and performing null/whitespace still throws the same CS8602 warning, as seen in the screenshot below.
Edit #2:
I’ve noticed that the code is written under .NET Standard 2.0. Upon testing the same code in .NET 6, I didn’t receive the same warning from the compiler. Given that I’m not a fan of using the null-forgiving operator, the workaround string input = parameter.Input ?? string.Empty;
could be the safe and straightforward way to manage the warning.
2
Answers
Yes, you misunderstand something. That is the devilish things people can do with C# that you don’t expect 🙂
You are checking a getter not a local variable. A getter is not required to return the same value on two different calls. Lets build a class that kills your "null check":
Oopsie.. but it wasn’t null. Really, it wasn’t when you checked. Just after that…
For your compiler to trust a null-check, it has to be something that cannot change between the check and the usage. The most obvious would be a local variable, since that is easy to assess whether it changed.
So your check should look like this:
The code is under .NET Standard 2.0. That version does not officially support nullable reference types. While it can be enabled by forcing a C# 8 version, the BCL-level support is not present. That means the String.IsNullOrWhitespace’s parameter will not be annotated with [NotNullWhen(false)]. Therefore, the nullable analysis will not work in this case as the compiler is not able to deduce the effects of IsNullOrWhitespace on nullability.