Why would I ever want to do object.ReferenceEquals(null, this) in Equals override?

551 views Asked by At

Consider the following code that I was reviewing:

public override bool Equals(object other)
{
    return !object.ReferenceEquals(null, this)
           && (object.ReferenceEquals(this, other)
           || ((other is MyType) && this.InternalEquals((MyType)other)));
}

The first line in this code triggered my curiosity. Whenever this is null, the method should return false. Now I am pretty sure the programmer meant to write !object.ReferenceEquals(other, null), to shortcut situations with null, but he's insistent that this can be null. I'm insistent that it cannot (unless someone uses direct memory manipulation). Should we leave it in?

2

There are 2 answers

5
Jon Skeet On BEST ANSWER

While I certainly wouldn't normally check this for nullity, it's possible, without any actual memory nastiness - just a bit of reflection:

using System;

public class Test
{
    public void CheckThisForNullity()
    {
        Console.WriteLine("Is this null? {0}", this == null);
    }

    static void Main(string[] args)
    {
        var method = typeof(Test).GetMethod("CheckThisForNullity");
        var openDelegate = (Action<Test>) Delegate.CreateDelegate(
               typeof(Action<Test>), method);
        openDelegate(null);
    }
}

Alternatively, generate IL which uses call instead of callvirt to call an instance method on a null target. Entirely legit, just not something the C# compiler would normally do.

This has nothing to do with finalization, which is hairy in its own right but in different ways. It's possible for a finalizer to run while an instance method is executing if the CLR can prove that you're not going to use any fields in the instance (which I would strongly expect to include the this reference).

As for the code presented - nope, that looks like it's just a mistake. I would rewrite it as:

public override bool Equals(object other)
{
    return Equals(other as MyType);
}

public bool Equals(MyType other)
{
    if (ReferenceEquals(other, null))
    {
        return false;
    }
    // Now perform the equality check
}

... assuming that MyType is a class, not a struct. Note how I'm using another public method with the right parameter type - I'd implement IEquatable<MyType> at the same time.

0
Theodoros Chatzigiannakis On

C# doesn't normally allow methods to be called on null. I think that the programmer who wrote that is either coming from a C++ background (where I think methods can be called on null, as long as they don't access a data member of this) or writing defensively for special scenarios (such as invocation by reflection, as has already been said).