3

I have a class that imlements IEquatable<T>. Is it necessary to do a refrence check in Equals() or is it taken care of in the framework?

class Foo : IEquatable<Foo>
{
    int value;
    Bar system;

    bool Equals(Foo other)
    {
        return this == other || 
        ( value == other.value && system.Equals(other.system) );
    }
}

In the above example is the this==other statement superfluous or necessary?

Update 1

I understand I need to correct the code as follows:

    bool Equals(Foo other)
    {
        if( other==null ) { return false; }
        if( object.ReferenceEquals(this, other) ) { return true; } //avoid recursion
        return value == other.value && system.Equals(other.system);
    }

Thanks for the replies.

John Alexiou
  • 28,472
  • 11
  • 77
  • 133

6 Answers6

4

It's generally an optimization - it would be a strange Equals implementation which would fail without it. I would therefore not regard it as necessary - but nor does it it "taken care of in the framework". I's a cheap optimization to achieve, so it's usually worth including.

Note that if you're also overloading ==, then you should probably use object.ReferenceEquals to perform these comparisons.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    @Andrew: That's an option, but I generally prefer being explicit with Object.ReferenceEquals - I find that more instantly readable. – Jon Skeet Jan 13 '11 at 16:34
4

Be careful. I would actually strongly discourage this since if you ever want to overload the == operator for your Foo type in terms of Equals (as is usually done in my experience) you'll find yourself with an infinite recursion.

To illustrate what I mean, here is a common implementation of == in terms of Equals:

public static bool operator ==(Foo x, Foo y)
{
    // Will overflow the stack if Equals uses ==:
    return !ReferenceEquals(x, null) && x.Equals(y);
}

That said, I can wholeheartedly agree with Jon's point that it may be appropriate to use ReferenceEquals instead.

Community
  • 1
  • 1
Dan Tao
  • 125,917
  • 54
  • 300
  • 447
  • Am I the only person who thinks the C# `==` operator is horrible? In vb.net, the equality-check operator may only be used on types which implement it; if one wishes to test for reference equality, one must use the `Is` operator or `IsNot` operators, which are only usable for either testing reference equality, or testing a nullable-type instance against `Nothing`. Using the same operator for reference equality and value equality, using non-virtual overloading, is a recipe for confusion. – supercat Jul 06 '12 at 19:56
  • @supercat: I like that it's there but feel that it's misused in the vast majority of cases. Basically, I would prefer to live in a world where `==` was always used for reference equality *for reference types*. (I would happily adhere to this rule even for strings, in fact.) But I do see the appeal for custom value types, at least. – Dan Tao Jul 06 '12 at 20:26
  • The proper thing to do, IMHO, would have been to do what vb.net does--use different operators for reference equality and logical equality. Having an operator for reference equality is helpful, but having one for what may or may not be reference equality, based upon static binding, is not. Consider: `public static bool IsEqual(T obj1, T obj2) where T : class { return obj1 == obj2; }` What should be the effect of calling `IsEqual` on two different `String` instances containing the same sequence of characters. – supercat Jul 06 '12 at 20:35
  • @supercat: I think we're in agreement. I guess my view is that we could have something like what you describe by convention if .NET developers would just resist the urge to overload `==` for their reference types and only use it for value types. That way it would de facto only ever represent reference equality (which means .NET developers would not be so confused by your example, which will return `false` for two like strings), except for value types such as `int`, `bool`, etc. and custom value types. – Dan Tao Jul 06 '12 at 21:05
  • It's ugly to have what looks like a value equality operator where two values of type `string` containing the same characters may compare unequal equal (per generics example above), and it's ugly not to have an equality operator that unconditionally tests for reference equality. I don't see any good solution other than having separate operators for reference equality and value equality. – supercat Jul 06 '12 at 21:08
  • @supercat: That argument hinges on the special-casing of `string`, though—which is fine, just not something I can totally get behind. I do agree that it's unintuitive (your generics example); but I view that more as a consequence of what we've come to expect given how "value-like" strings are in .NET, and the simple fact that whoever authored the `System.String` class chose to overload the `==` in that manner. I'd really be fine with `==` testing for reference equality for strings, for the same reason that I'm fine with it returning `false` for two arrays or lists containing the same elements. – Dan Tao Jul 06 '12 at 21:43
  • In vb.net, the overload of the equality and inequality operators on `System.String` doesn't cause any confusion or ambiguity, since such operators cannot invoke anything other than type-specific overloads. Saying "If s1=s2 Then...` will test for identical sequences of characters; saying `If s1 Is s2` will test for identical references. As for comparing arrays, I really really wish .net had included an immutable-array type, which overrode `Equals` to check members for equality (and possibly overloaded the equality operator likewise). Type `String` would essentially be `ImmutableArray`. – supercat Sep 23 '12 at 22:40
1

It's not necessary in the sense that it may not be required for correctness, but the framework certainly does not "take care of it", so it may be useful to put in, typically for performance reasons.

One point: if the implementation is wrapped by EqualityComparer<T>.Default, it doesn't enter the user code if one or both of the arguments are null, so in that case it does perform some measure of reference checking (if not a full ReferenceEquals(x, y)).

public override bool Equals(T x, T y)
{
    if (x != null)
    {
        return ((y != null) && x.Equals(y));
    }
    if (y != null)
    {
        return false;
    }

    return true;
}

Off-topic, there are several null-dereferencing issues in your sample method (other might be null, this.system might be null).

I would write your method as something like:

public bool Equals(Foo other)
{
    if(other == null)
         return false;

    if(other == this)
         return true;

    return value == other.value
            && EqualityComparer<Bar>.Default.Equals(bar, other.bar)
            // You don't *have to* go down the EqualityComparer route
            // but you do need to make sure you don't dereference null.

}

Also remember to override GetHashCode whenever you write your own equality-comparisons.

Ani
  • 111,048
  • 26
  • 262
  • 307
0

I think it is necessary to check this == other, because you define your own equals. If you don't want it to be pointer-checked, you write your own IEquatable.

Marnix
  • 6,384
  • 4
  • 43
  • 78
0

IEquatable<T> is an interface; the implementation is up to the implementer.

Since you are implementing the interface you are responsible for all expected behavior as defined by the interface.

Aaron McIver
  • 24,527
  • 5
  • 59
  • 88
-1

I believe that it's necessary. The reference check is the first, quick step you can perform when comparing objects.

In the example you have given, be sure to check that other is not null before accessing its values.

bool Equals(Foo other)
{
    if(other == null) return false;

    if(this == other) return true;

    // Custom comparison logic here.
}
Tomas McGuinness
  • 7,651
  • 3
  • 28
  • 40
  • In what way is it necessary rather than an optimization? How would you expect the behaviour to differ if you removed it? – Jon Skeet Jan 13 '11 at 16:32
  • On consideration, you're right, it's not necessary, but it's a very simple way to tell if the objects you're comparing are equal especially if you have to compare several properties to determine eqality. I think my definition of necessary in this case would be "I'd encourage it" ;) – Tomas McGuinness Jan 13 '11 at 16:41
  • 1
    I find it hard to see why this answer was accepted, given that its first statement is incorrect... – Jon Skeet Jan 13 '11 at 17:50