Search code examples
c#inheritancenullabstract-classnull-check

Why does null check fail even though object is explicitly initialized as null


I have created a custom abstract class, which in turn of course derived classes were also created.

public abstract class AbstractBaseClass
...

public class ChildClass1 : AbstractBaseClass
...

Now, whenever I declare for example AbstractBaseClass baseClass = null, and wherever null checks follow after this initialization, it always fails.

if (baseClass == null)
{
    // this block is never reached - condition always evaluates to false
    // let's say AbstractBaseClass baseClass = null is at line 10
    // even if this condition is at line 11, condition still fails
}

Reason why there is a null check is because there are multiple derived classes, and on some process, I determine which type would it be (e.g. using switch cases). And of course there are invalid cases, in which I expect that the value would be the initialized null.

This is really weird, and I really am expecting that null check would evaluate to true.

What could be the possible causes why this happens (so that I can add more sample code depending on the info as the whole relevant code is quite big), and how should one fix this? Thank you.

EDIT:

Also, debugger value is null.

Oh that's right, as @taffer mentioned, == is overloaded for AbstractBaseClass. Here is that part and other relevant code:

    protected bool Equals(AbstractBaseClass other)
    {
        return Equals(this.SomeUniqueProperty, other.SomeUniqueProperty);
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj))
        {
            return false;
        }

        if (ReferenceEquals(this, obj))
        {
            return true;
        }

        return obj.GetType() == this.GetType() && this.Equals((AbstractBaseClass)obj);
    }

    public override int GetHashCode()
    {
        return (this.SomeUniqueProperty != null ? this.SomeUniqueProperty.GetHashCode() : 0);
    }

    public static bool operator ==(AbstractBaseClass a, AbstractBaseClass b)
    {
        if (ReferenceEquals(null, a))
        {
            return false;
        }

        return !ReferenceEquals(null, b) && a.Equals(b);
    }

    public static bool operator !=(AbstractBaseClass a, AbstractBaseClass b)
    {
        return !(a == b);
    }

Solution

  • Your == overload is wrong, as you are returning false if a is null, ignoring the fact that b could also be null.

    What you need to do is return true if both are null, or if a equals b:

    public static bool operator ==(AbstractBaseClass a, AbstractBaseClass b)
    {
        var isANull = ReferenceEquals(null, a);
        var isBNull = ReferenceEquals(null, b)
        return (isANull && isBNull) || a?.Equals(b) ?? false;
    }
    

    Note: In case a is null but b is not, the .? operator will return null, and the ?? operator will return false.

    As RufusL wrote in the comments, there's a shorter eqiuvalent code to get the same results:

    public static bool operator ==(AbstractBaseClass a, AbstractBaseClass b)
    {
        return a?.Equals(b) ?? ReferenceEquals(null, b);
    }
    

    if a is null, return true if b is also null. if a is not null, return the result of a.Equals(b).

    In case a is not null but b is, your Equals method should return false:

    protected bool Equals(AbstractBaseClass other)
    {
        return other != null 
            ? Equals(this.SomeUniqueProperty, other.SomeUniqueProperty) 
            : false;
    }