Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When can a null check throw a NullReferenceException

I know this might seem impossible at first and it seemed that way to me at first as well, but recently I have seen exactly this kind of code throw a NullReferenceException, so it is definitely possible.

Unfortunately, there are pretty much no results on Google that explain when code like foo == null can throw a NRE, which can make it difficult to debug and understand why it happened. So in the interest of documenting the possible ways this seemingly bizarre occurrence could happen.

In what ways can this code foo == null throw a NullReferenceException?

like image 924
The Red Fox Avatar asked Jan 05 '21 17:01

The Red Fox


People also ask

Why am I getting a NullReferenceException?

So, a reference is what a variable of a reference type contains. These variables can point to “nothing”, though, and that's what we call a null reference: a reference that doesn't point to any object. When you try to call a method or another member on the said variable, you got the NullReferenceException.

How do I fix NullReferenceException in C#?

To prevent the NullReferenceException exception, check whether the reference type parameters are null or not before accessing them. In the above example, if(cities == null) checks whether the cities object is null or not. If it is null then display the appropriate message and return from the function.

How do you throw an exception when an object is null?

The way you have it is correct. The Null-conditional Operator only returns NULL . There's no shortcut to throw an exception but one of the things you can do is shorten checks like if (Foo == null || Foo. Bar == null || Foo.

How do I fix this error system NullReferenceException object reference not set to an instance of an object?

The best way to avoid the "NullReferenceException: Object reference not set to an instance of an object” error is to check the values of all variables while coding. You can also use a simple if-else statement to check for null values, such as if (numbers!= null) to avoid this exception.


4 Answers

in C# you can overload operators to add custom logic on some comparison like this. For example:

class Test
{
    public string SomeProp { get; set; }
    
    public static bool operator ==(Test test1, Test test2)
    {
        return test1.SomeProp == test2.SomeProp;
    }

    public static bool operator !=(Test test1, Test test2)
    {
        return !(test1 == test2);
    }
}

then this would produce a null reference exception:

Test test1 = null;
bool x = test1 == null;
like image 193
Jonesopolis Avatar answered Oct 21 '22 13:10

Jonesopolis


One example is with getters:

class Program
{
    static void Main(string[] args)
    {
        new Example().Test();
    }
}

class Example
{
    private object foo
    {
        get => throw new NullReferenceException();
    }

    public void Test()
    {
        Console.WriteLine(foo == null);
    }
}

This code will produce a NullReferenceException.

like image 42
ekke Avatar answered Oct 21 '22 13:10

ekke


While quite esoteric, it is possible to cause this type of behavior via custom implementations of DynamicMetaObject. This would be a rare but interesting example of where this could occur:

void Main()
{
    dynamic foo = new TestDynamicMetaObjectProvider();
    object foo2 = 0;
    
    Console.WriteLine(foo == foo2);
}

public class TestDynamicMetaObjectProvider : IDynamicMetaObjectProvider
{
    public DynamicMetaObject GetMetaObject(Expression parameter)
    {
        return new TestMetaObject(parameter, BindingRestrictions.Empty, this);
    }
}

public class TestMetaObject : DynamicMetaObject
{
    public TestMetaObject(Expression expression, BindingRestrictions restrictions)
        : base(expression, restrictions)
    {
    }

    public TestMetaObject(Expression expression, BindingRestrictions restrictions, object value)
        : base(expression, restrictions, value)
    {
    }

    public override DynamicMetaObject BindBinaryOperation(BinaryOperationBinder binder, DynamicMetaObject arg)
    {
        // note it doesn't have to be an explicit throw.  Any improper property
        // access could bubble a NullReferenceException depending on the 
        // custom implementation.
        throw new NullReferenceException();
    }
}
like image 9
David L Avatar answered Oct 21 '22 11:10

David L


Not literally your code, but awaiting a null task will also throw:

public class Program
{
    public static async Task Main()
    {
        var s = ReadStringAsync();
        if (await s == null)
        {
            Console.WriteLine("s is null");
        }
    }

    // instead of Task.FromResult<string>(null);
    private static Task<string> ReadStringAsync() => null;
}

Do note however that the debugger can get the location of throwing statements wrong. It might show the exception thrown at the equality check, while it occurs at earlier code.

like image 7
CodeCaster Avatar answered Oct 21 '22 13:10

CodeCaster