1

For the life of me, I can't get my WPF binding to work correctly for a RibbonComboBox's SelectedItem property.

Then I started reading about how .NET compares items. My understanding is that, in some cases, it compares the actual pointer. In which case, loading a new and equal value from a database, for example, it may not be considered equal.

So then I started looking into explicitly implementing Equals for my type. However, this seems a bit confusing as there are at least two different versions I can implement.

The code below shows I can either override object.Equals, or I can implement IEquatable<>. In fact, the code below implements both, and testing indicates that both are called.

public class TextValuePair : IEquatable<TextValuePair>
{
    public string Text { get; set; }
    public int Value { get; set; }

    public override bool Equals(object obj)
    {
        if (obj == null || !(obj is TextValuePair))
            return false;
        return Value == (obj as TextValuePair).Value;
    }

    public override int GetHashCode()
    {
        return Value;
    }

    public bool Equals(TextValuePair obj)
    {
        Debug.Assert(obj != null);
        if (obj == null)
            return false;
        return Value == obj.Value;
    }
}

Can someone help me understand what is required to avoid my objects from being compared for equivalence by .NET library routines according to pointers having the same value? Is it really necessary to implement both versions of Equals?

Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466
  • They are many possible wayst to implement `Equals`, but why don't you just choose simply to `override Equals`, as it will be always used. Is it not working in your case? – meJustAndrew Aug 12 '16 at 15:21
  • @meJustAndrew: My binding still has issues but that is likely unrelated at this point. Since both versions of `Equals` are being called, how do I know that the override is enough and will always be used? Two versions being called sort of leaves me not knowing when which each will be called. – Jonathan Wood Aug 12 '16 at 15:23
  • 2
    See: http://stackoverflow.com/questions/2734914/whats-the-difference-between-iequatable-and-just-overriding-object-equals – Arno van Lieshout Aug 12 '16 at 15:27
  • 1
    Yeah, the equality stuff is a bit of a mess in .NET, and not all libraries invoke the `Equals` method(s) the same way. To help you further, you'll need to post more info on the binding portion of the code to see which library calls are involved. Also, I'll just mention for completeness that basing the hash code on a mutable property is dangerous. Hopefully, this is unrelated to your problem. – sstan Aug 12 '16 at 15:33
  • 2
    You could just implement the first `Equals()` as: `public override bool Equals(object obj) { return Equals(obj as TextValuePair); }` as long as you're implementing `IEquatable`. – itsme86 Aug 12 '16 at 15:34
  • 2
    The override of `Equals(object)` will always be called if you don't implement `IEquatable`. `IEquatable` is preferred since it is more precise and performs better. – Lee Aug 12 '16 at 15:35
  • Another thing that hasn't been mentioned is that `Equals()` might never be called if using a keyed collection and `GetHashCode()` returns unique values. http://stackoverflow.com/a/371348/1141432 – itsme86 Aug 12 '16 at 15:37
  • I'd also like to reiterate the point that @sstan made about `GetHashCode()` being based on a mutable value. That can *really* mess with a collection like `Dictionary<,>` or `HashSet<>`. – itsme86 Aug 12 '16 at 15:42
  • @sstan: Can you elaborate on the problems of implementing `GetHashCode()` as I've done? Is the issue with cases where this value could change? I guess that would make sense, although not an issue for me. – Jonathan Wood Aug 12 '16 at 15:46
  • See [this article](https://ericlippert.com/2011/02/28/guidelines-and-rules-for-gethashcode/) written by Eric Lippert. Specifically, look for the part that talks about *Rule: the integer returned by GetHashCode must never change while the object is contained in a data structure that depends on the hash code remaining stable*. It'll explain it better than I can in a short comment. – sstan Aug 12 '16 at 15:58

1 Answers1

2

As pointed by msdn, if you are implementing IEquatable<T> you will still need to override Equals because it will still be called with the signature Equals(System.Object, System.Object) and yhe override should be consistent with the methods implemented from IEquatable<T>.

Also as in the question about the difference between iequatable and just overriding object equals which Arno showed in the comment, IEquatable<T> is used when operations on collections are required to optimize them, not to need the boxing anymore, and instead call the direct Equals with the specific type.

You have two options:

If you are interested in performance when you are working with collections in your program, you could keep implementing the both Equals methods;

or

You could just remove the IEquatable<T> and only override Equals to simplify your code.

Additionally, whenever you override Equals, you should also always override GetHashCode as well.

Community
  • 1
  • 1
meJustAndrew
  • 6,011
  • 8
  • 50
  • 76
  • Yes, it looks like `object.Equals()` used to be the only way to override comparisons. But since it requires boxing value types, the newer `IEquatable<>` was added to be faster. For performance reasons, it appears you should implement both. However, when you say _it will still be called with the signature Equals(System.Object, System.Object)_, do you know it what case that version is called? – Jonathan Wood Aug 12 '16 at 15:41
  • @JonathanWood this is a good question too, it will be called if you do `Object.Equals(objectA, objectB)`, where this could be boxed around different types, and they can still be equal, for a given Equals override and if they have the same properties. – meJustAndrew Aug 12 '16 at 15:53