Search code examples
c#.net-coreannotationsnullreferenceexception

Dereference of a possibly null reference when using Extension Methods with Annotation


I have the following extension method for IsNotNull and it works fine but I get warning when using it that there may be a null reference and I am trying to figure out how to remove that warning Dereference of a possibly null reference.

Method

    [ContractAnnotation("obj:null => false")]
    public static bool IsNotNull(this object obj)
    {
        return obj != null;
    }

the yellow line I am trying to remove

enter image description here


Note:

I am aware of ! and can use that to suppress the warning but I am trying to figure out the "right way"

    if (actions.IsNotNull())
    {
        actions!.Invoke(builder);
    }

Solution

  • A couple ways to fix this

    Option one: inform the compiler about your nullability check.

    The C# compiler isn't smart enough to investigate how IsNotNull works. It doesn't know that when you return true then obj cannot be null. There are Nullable static analysis attributes you can apply to inform the compiler.

    public static bool IsNotNull([NotNullWhen(true)] this object? obj)
    {
        return obj != null;
    }
    

    [NotNullWhen(true)], applied to the parameter, let's the C# compiler understand that returning true means that obj is not null. You will also want to make sure that the obj parameter is a nullable object (object?).

    Option two: why do you even need the IsNotNull method?

    As written, IsNotNull is rather basic. It might be easier to just stick with doing the nullability check yourself.

    if (actions is not null)
    {
        actions.Invoke(builder);
    }
    

    Option three: Run Invoke conditionally

    Last, you could save yourself a lot of time by using the ?. operator. This will run the Invoke() method on the actions object, but only if the actions object is not null.

    // there is no "if" around this code, nor any need for IsNotNull()
    actions?.Invoke(builder);
    

    Option three's code is compiled to the same thing as what you would have typed in option two.