7

Possible Duplicate:
How do I check for nulls in an '==' operator overload without infinite recursion?

When I overload the == operator for objects I typically write something like this:

    public static bool operator ==(MyObject uq1, MyObject uq2) {
        if (((object)uq1 == null) || ((object)uq2 == null)) return false;
        return uq1.Field1 == uq2.Field1 && uq1.Field2 == uq2.Field2;
    }

If you don't down-cast to object the function recurses into itself but I have to wonder if there isn't a better way?

Community
  • 1
  • 1
George Mauer
  • 117,483
  • 131
  • 382
  • 612
  • 1
    See this link too for a proper all round implementation http://stackoverflow.com/questions/104158/what-is-best-practice-for-comparing-two-instances-of-a-reference-type – nawfal Dec 16 '12 at 11:02

7 Answers7

7

As Microsoft says,

A common error in overloads of operator == is to use (a == b), (a == null), or (b == null) to check for reference equality. This instead results in a call to the overloaded operator ==, causing an infinite loop. Use ReferenceEquals or cast the type to Object, to avoid the loop.

So use ReferenceEquals(a, null) || ReferenceEquals(b, null) is one possibility, but casting to object is just as good (is actually equivalent, I believe).

So yes, it seems there should be a better way, but the method you use is the one recommended.

However, as has been pointed out, you really SHOULD override Equals as well when overriding ==. With LINQ providers being written in different languages and doing expression resolution at runtime, who knows when you'll be bit by not doing it even if you own all the code yourself.

Philip Rieck
  • 32,368
  • 11
  • 87
  • 99
  • Yes, it's a common problem but the solution is to override the Equals function and make the operator overload call Equals. ReferenceEquals solves a different problem and provides a completely different type of equality. – Scott Dorman Sep 17 '08 at 20:07
  • 2
    I think you misunderstood the ReferenceEquals calls above. I'm simply testing for equality with NULL, with the understanding of doing an actual equality check in addition. NOT calling referenceequals to test equality of the arguments. – Philip Rieck Sep 17 '08 at 20:10
2

ReferenceEquals(object obj1, object obj2)

Juanma
  • 3,961
  • 3
  • 27
  • 26
2

@neouser99: That's the right solution, however the part that is missed is that when overriding the equality operator (the operator ==) you should also override the Equals function and simply make the operator call the function. Not all .NET languages support operator overloading, hence the reason for overriding the Equals function.

Scott Dorman
  • 42,236
  • 12
  • 79
  • 110
0
if ((object)uq1 == null) 
    return ((object)uq2 == null)
else if ((object)uq2 == null)
    return false;
else
    //return normal comparison

This compares them as equal when both are null.

Timothy Carter
  • 15,459
  • 7
  • 44
  • 62
  • 1
    This does the same thing that my example does just in more convoluted terms – George Mauer Sep 17 '08 at 20:04
  • No it doesn't @GeorgeMauer - yours returns false if both of them are `null`. Timothy's solution rightfully returns `true` in that scenario. – mjwills Oct 26 '22 at 04:52
0

Just use Resharper to create you Equals & GetHashCode methods. It creates the most comprehensive code for this purpose.

Update I didn't post it on purpose - I prefer people to use Resharper's function instead of copy-pasting, because the code changes from class to class. As for developing C# without Resharper - I don't understand how you live, man.

Anyway, here is the code for a simple class (Generated by Resharper 3.0, the older version - I have 4.0 at work, I don't currently remember if it creates identical code)

public class Foo : IEquatable<Foo>
{
    public static bool operator !=(Foo foo1, Foo foo2)
    {
        return !Equals(foo1, foo2);
    }

    public static bool operator ==(Foo foo1, Foo foo2)
    {
        return Equals(foo1, foo2);
    }

    public bool Equals(Foo foo)
    {
        if (foo == null) return false;
        return y == foo.y && x == foo.x;
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(this, obj)) return true;
        return Equals(obj as Foo);
    }

    public override int GetHashCode()
    {
        return y + 29*x;
    }

    private int y;
    private int x;
}
ripper234
  • 222,824
  • 274
  • 634
  • 905
  • 1
    And you wouldn't by any chance want to post it for those of us who don't have $400 to drop? – George Mauer Sep 17 '08 at 20:40
  • Why would Bill Wagner disagree with you in this chapter? http://my.safaribooksonline.com/book/programming/csharp/0321245660/csharp-language-elements/ch01lev1sec9 He babbles something about Equals being symmetric. – Hamish Grubijan Feb 17 '11 at 20:15
  • 1
    @Hamish - I don't know, you'll have to be more specific than that. – ripper234 Feb 17 '11 at 20:27
  • Equality must be symmetric. What if a class D extends class B. What you never want is b.Equals(d) not be the same as d.Equals(b). So, Equals(object obj) should also: A) Check for obj == null, B) Check for this.GetType() == obj.GetType(). That's what he said. – Hamish Grubijan Feb 17 '11 at 21:07
  • This implementation does contain a null check, although not a type check. It's nice to have in real code, although strictly speaking you should check the type. – ripper234 Feb 17 '11 at 23:53
  • This answer has many catches, 1 it doesnt answer to OP's original requirement that "if either of them are null then `==` should return false". In your case `null == null` returns true. 2, you dont need the `if (ReferenceEquals(this, obj)) return true;` inside your overriden `Equals` because that will be done essentially by your `static Equals(obj, obj)` method. May be you will need it better to speed up things inside `generic Equals`.See this link for a correct implementation http://stackoverflow.com/questions/104158/what-is-best-practice-for-comparing-two-instances-of-a-reference-type – nawfal Dec 16 '12 at 10:59
  • 3) its better to have `!=` as a negation of `==` operator rather than `Equals` method. Just for brevity.. – nawfal Dec 16 '12 at 23:22
-1

But why don't you create an object member function? It can certainly not be called on a Null reference, so you're sure the first argument is not Null.

Indeed, you lose the symmetricity of a binary operator, but still...

(note on Purfideas' answer: Null might equal Null if needed as a sentinel value of an array)

Also think of the semantics of your == function: sometimes you really want to be able to choose whether you test for

  • Identity (points to same object)
  • Value Equality
  • Equivalence ( e.g. 1.000001 is equivalent to .9999999 )
xtofl
  • 40,723
  • 12
  • 105
  • 192
  • 1
    I'm sorry this really doesn't answer the question. The question is if there is a better way to test for equality other than downcasting – George Mauer Sep 17 '08 at 20:13
-2

Follow the DB treatment:

null == <anything> is always false
Purfideas
  • 3,288
  • 1
  • 24
  • 17