Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 403
Andreas Koder Avatar asked Apr 23 '20 09:04

Andreas Koder


People also ask

What is a nullable type in C#?

The Nullable type allows you to assign a null value to a variable. Nullable types introduced in C#2.0 can only work with Value Type, not with Reference Type. The nullable types for Reference Type is introduced later in C# 8.0 in 2019 so that we can explicitly define if a reference type can or can not hold a null value.

What is Pragma warning in C#?

C# provides a feature known as the #pragma feature to remove the warnings. Sometimes we declare a variable but do not use the variable anywhere in the entire program so when we debug our code the compiler gives a warning so using the #pragma we can disable these types of warnings.


3 Answers

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.

like image 167
Drew Noakes Avatar answered Oct 18 '22 21:10

Drew Noakes


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; 
}
like image 5
Andreas Koder Avatar answered Oct 18 '22 22:10

Andreas Koder


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.

like image 3
Mikolaj Avatar answered Oct 18 '22 20:10

Mikolaj