skip to Main Content

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.

enter image description here

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.

enter image description here

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


  1. 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":

    public class DestroyYourNullCheck : IParameter
    {
        private bool checked = false;
    
        public string? Input 
        {
            get 
            {
                if(checked) return null; // boom
    
                checked = true;
                return "NonNullString";
            }
            set {}
        } 
    }
    

    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:

    public static string[] SeeTheFalseWarning(this IParameter parameter)
    {
        var input = parameter.Input; // local variable, getter evaluated exactly once
    
        // local variable null checked
        if (string.IsNullOrWhiteSpace(input))
        {
            throw new InvalidOperationException("Input must have value");
        }
    
        // compiler knows for sure local variable cannot possibly have changed since the null check:
        return input.Split(':');
    }
    
    Login or Signup to reply.
  2. 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search