Andreas Koder
Andreas Koder

Reputation: 445

How to suppress Possible Null Reference warnings

I am playing with the nullable types in c# 8 and I found a problem that is bugging me. Suppose I have a method which takes a nullable parameter. When a parameter is null, I want to throw a specific Exception. But I want the method to be clean and check the parameter somewhere else. The check method throws an exception, so after the method the parameter can not be null. Unfortunately, the compiler does not see that and throws warnings at me. Here's the method:

    public void Foo(string? argument)
    {
        GuardAgainst.Null(argument, nameof(argument));
        string variable = argument; // <-- Warning CS8600  Converting null literal or possible null value to non - nullable type
        var length = argument.Length; //<--Warning CS8602  Dereference of a possibly null reference
    }

Here's the check method:

    public static void Null(string? text, string paramName)
    {
        if (text == null)
            throw new ArgumentNullException(paramName);
    }

Now, I can suppress the warning like this:

#pragma warning disable CS8602
var length = argument.Length;
#pragma warning restore CS8602

but it kind of kills my intention to keep my code clean. So my question is: is there a nicer way to suppress the warnings? Or maybe tell a compiler that from now on the parameter is guaranteed to not be null?

Upvotes: 21

Views: 45395

Answers (3)

Drew Noakes
Drew Noakes

Reputation: 311305

This does what you want:

public static void Null<T>([NotNull] T? value, string paramName)
{
    if (value == null)
        throw new ArgumentNullException(paramName);
}

The [NotNull] attribute instructs the analysis that, after calling this method, value will not be null.

This means you don't need the ! operator, which is much cleaner and more natural.

void M(string? argument)
{
    GuardAgainst.Null(argument, nameof(argument));
    string variable = argument; // no warning
    // ...
}

The use of an unconstrained generic type parameter T here means that this approach works for both reference types (such as string) and nullable value types (such as int?).

If you're using .NET 6, you can simplify this even further via CallerArgumentExpressionAttribute as follows:

public static void Null<T>(
    [NotNull] T? value,
    [CallerArgumentExpression(parameterName: "value")] string? paramName = null)
{
    if (value == null)
        throw new ArgumentNullException(paramName);
}

With that, the second argument can be omitted, and the caller can be simplified to:

GuardAgainst.Null(argument);

Think of the ? specifier on a type as meaning two things: 1) the value can be null before the call, and 2) the value can be null afterwards. Another way of writing it is [AllowNull, MaybeNull]. The absence of ? in a nullable context equally means [DisallowNull, NotNull]. In the case of your Null method, we end up with [AllowNull, NotNull] due to the manual specification of NotNull.

Upvotes: 16

Mikolaj
Mikolaj

Reputation: 1909

Consider this solution with the null-coalescing operator ??

The null-coalescing operator ?? returns the value of its left-hand operand if it isn't null; otherwise, it evaluates the right-hand operand and returns its result. The ?? operator doesn't evaluate its right-hand operand if the left-hand operand evaluates to non-null.

public void Foo(string? argument)
{
    string variable = argument ?? throw new ArgumentNullException(nameof(argument));
    var length = argument.Length;
}

This solution is much cleaner in my opinion. You avoid inspecting GuardAgainst class and .Null() static method implemetation details.

Upvotes: 6

Andreas Koder
Andreas Koder

Reputation: 445

Ok, it looks like there is a really simple solution to it - the ! operator You have to use it once after the guard, and then it considered to be not null:

public void Foo(string? argument)
{
    GuardAgainst.Null(argument, nameof(argument));
    var length = argument!.Length; 
}

Upvotes: 13

Related Questions