19

when I try to overload operator == and != in C#, and override Equal as recommended, I found I have no way to distinguish a normal object and null. For example, I defined a class Complex.

public static bool operator ==(Complex lhs, Complex rhs)
{
    return lhs.Equals(rhs);
}

public static bool operator !=(Complex lhs, Complex rhs)
{
    return !lhs.Equals(rhs);
}

public override bool Equals(object obj)
{
    if (obj is Complex)
    {
        return (((Complex)obj).Real == this.Real &&
                   ((Complex)obj).Imaginary == this.Imaginary);
    }
    else
    {
        return false;
    }
}

But when I want to use

if (temp == null)

When temp is really null, some exception happens. And I can't use == to determine whether the lhs is null, which will cause infinite loop.

What should I do in this situation.

One way I can think of is to us some thing like Class.Equal(object, object) (if it exists) to bypass the == when I do the check.

What is the normal way to solve the problem?

Thank you.

LLS
  • 2,128
  • 2
  • 23
  • 36
  • possible duplicate of [How do I check for nulls in an '==' operator overload without infinite recursion?](http://stackoverflow.com/questions/73713/how-do-i-check-for-nulls-in-an-operator-overload-without-infinite-recursion) – Sam Jan 19 '14 at 04:18

5 Answers5

14

You can use the following at the top of your Equals override:

if (Object.ReferenceEquals(obj, null))
    return false;

The exception you are getting is probably a StackOverflowException because your == operator will cause infinite recursion.

EDIT:

If Complex is a struct you should not have any problems with NullReferenceExceptions. If Complex is a class you can change your implementation of the == and != operator overloads to avoid the exception (Laurent Etiemble already pointed this out in his answer):

public static bool operator ==(Complex lhs, Complex rhs)
{
    return Equals(lhs, rhs);
}

public static bool operator !=(Complex lhs, Complex rhs)
{
    return !Equals(lhs, rhs);
} 
Jakob Christensen
  • 14,826
  • 2
  • 51
  • 81
  • Actually it's Object reference not set to an instance of an object. It should work, thanks. :) – LLS Jun 09 '10 at 12:59
  • The exception still exists, since null.Equals() is attempted to be called. – LLS Jun 09 '10 at 13:02
  • I'd consider making Complex a struct instead of a class. – Jakob Christensen Jun 09 '10 at 13:19
  • That's true. It just an example. And thanks anyway. (Actually Microsoft has already implemented Complex, so there is no need to create one in real life) – LLS Jun 09 '10 at 13:39
13

You should consider using the static Equals method in the operator overloads (which will call the instance Equals method):

public static bool operator ==(Complex lhs, Complex rhs)
{
    return Equals(lhs, rhs);
}

public static bool operator !=(Complex lhs, Complex rhs)
{
    return !Equals(lhs, rhs);
}

Note: You may also check for null in the Equals method.

You can also read the Object.Equals Topic on MSDN, which is a great source of samples.

Laurent Etiemble
  • 27,111
  • 5
  • 56
  • 81
  • Thanks, it works, but I'm not sure why. And, why can Object be omitted in Object.Equals()? And I didn't find why this can prevent the null problem in MSDN. (Does it check null first?) – LLS Jun 09 '10 at 13:21
  • 1
    You don't need the Object class prefix because Complex inherit from Object; Complex see the Object's static methods. I don't know the internals of the static Equals method, but it likely check for null before calling the instance Equals method. – Laurent Etiemble Jun 09 '10 at 13:28
  • 1
    If lhs is not null the static Equals calls the instance method Equals on lhs. If lhs is null Equals compares the references of lhs and rhs. – Jakob Christensen Jun 09 '10 at 13:35
  • Thank you. It seems to be an elegant solution. – LLS Jun 09 '10 at 13:40
3
public static bool operator ==(Complex lhs, Complex rhs)
{
    if (Object.ReferenceEquals(lhs, null))
    {
        return Object.ReferenceEquals(rhs, null);
    }

    return lhs.Equals(rhs);
}

public static bool operator !=(Complex lhs, Complex rhs)
{
    return !(lhs == rhs);
}

Poor man's unit test

Action<Complex, Complex> tester = (left, right) =>
{
    Console.WriteLine(left == right);
    Console.WriteLine(left != right);
    Console.WriteLine(left == null);
    Console.WriteLine(left != null);
    Console.WriteLine("---");
};

tester(new Complex(), new Complex());
tester(null, new Complex());
tester(null, null);
tester(new Complex(), null);
Anthony Pegram
  • 123,721
  • 27
  • 225
  • 246
0

There is a better approach then using operators is and cast:

Complex c = obj as Complex;
return (c != null) && (c.Real == this.Real) && (c.Imaginary == this.Imaginary);

Here is a quick test concerning Equals operator override and comparing with null:

class Complex
{
    public override bool Equals(object obj)
    {
        if (obj is Complex)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

Debugging doesn't step into operator's body:

var b = (new Complex() == new Complex());
abatishchev
  • 98,240
  • 88
  • 296
  • 433
  • Thanks, but it seems that c != null will cause infinite loop. – LLS Jun 09 '10 at 12:52
  • @LLS: Really? Interesting. Not sure that comparing with `null` will use `object` comparing operator. But maybe.. – abatishchev Jun 09 '10 at 13:02
  • I haven't tested it yet, but it was a caution in the text book. And I did encounter this problem when I tried to recursively call ==. – LLS Jun 09 '10 at 13:17
0

I think you shoud test for null in the == operator implementation. Otherwise, when lhs is null, you'd call Complex(null).Equals (I don't know for C#, but in Java this would be a Nullpointer Exception)

To test for null, I suggest something like:

if (null == lhs && null == rhs) return true
else if (null == lhs) return false
else return lhs.Equals(rhs);

So Object.Equals will be called for all == comparisons above.

nang
  • 421
  • 6
  • 16
  • You get a recursive call to the == operator. –  Jun 09 '10 at 13:16
  • Ok, interesting. Just being curious, how comes that operator ==(Complex, Complex) is called, when I test for null == lhs? How does the compiler decide that "null" is of type Complex? – nang Jun 09 '10 at 13:22