4

I'm trying to perform a good comparison when I use List.Contains(T item).

The problem is that I'm using BaseItem as a list item. And I need to verify if one object inside of the list has the same properties values that the object which I plan to add.

For example:

public abstract class BaseItem
{
    // some properties

    public override bool Equals(object obj)
    {
        return obj != null && this.GetType() == obj.GetType();
    }
}

public class ItemA : BaseItem
{
    public int PropertyA { get; set; }

    public override bool Equals(object obj)
    {
        if (base.Equals(obj) == false)
            return false;

        return (this.PropertyA == (obj as ItemA).PropertyA;
    }
}

public class ItemB : BaseItem
{
    public int PropertyB { get; set; }

    public override bool Equals(object obj)
    {
        if (base.Equals(obj) == false)
            return false;

        return this.PropertyB == (obj as ItemB).PropertyB;
    }
}

public class Program
{
    static void Main(string[] args)
    {
        List<BaseItem> items = new List<BaseItem>()
        {
            new ItemB() { PropertyB = 3 },
            new ItemA() { PropertyA = 2 },
            new ItemB() { PropertyB = 2 }
        };

        BaseItem newItem = new ItemA() { PropertyA = 2 };
        items.Contains(newItem);  // should return 'True', because the first element is equals than 'newItem'
    }
}

I'm not sure if it's correct to override Equals method or should I have to implement IEquality interface.

Darf Zon
  • 6,268
  • 20
  • 90
  • 149
  • 2
    So the first thing that I notice is that if you pass an `ItemB` to `ItemA`'s `Equals` method it will throw a null pointer exception. You should write it so that it will just return false instead. (You need to null check the result of the `as` operation.) – Servy Jul 18 '12 at 16:37

1 Answers1

3

The standard way to test for collection membership (list membership, hashset membership, ...) is to use the .Contains method, which in turn uses IEquatable<T>.Equals. The default implementation of IEquatable<T>.Equals (if you do not provide your own implementation) uses Object.Equals(Object)).

You can certainly implement IEquatable<T>. This will improve performance of the Contains check slightly. See msdn.microsoft.com/en-us/library/ms131190.aspx.

If you implement IEquatable<T> you should still override Object.Equals and Object.GetHashCode to provide consistent behavior

If you implement Equals, you should also override the base class implementations of Object.Equals(Object) and GetHashCode so that their behavior is consistent with that of the IEquatable.Equals method.

http://msdn.microsoft.com/en-us/library/ms131190.aspx

See this question for a related discussion

Simplify Overriding Equals(), GetHashCode() in C# for Better Maintainability

Community
  • 1
  • 1
Eric J.
  • 147,927
  • 63
  • 340
  • 553
  • That would be the case for a `HashSet`, `Dictionary`, and a number of others, but not List. It won't rely on `GetHashCode`. – Servy Jul 18 '12 at 16:35
  • @Servy: My understanding is that `List.Contains` uses `IEquatable.Equals` (as does by the way `Dictionary.Contains`) http://msdn.microsoft.com/en-us/library/ms131190.aspx If you do not specifically implement `IEquatable`, `Object.Equals` would be used instead. Do I understand something incorrectly? – Eric J. Jul 18 '12 at 16:54
  • No, your comment is entirely correct. My point is that given IEqualtable isn't implemented, and he's using a `List` rather than a `Dictionary` he doesn't *have* to override `GetHashCode` for it to work. It is generally a good idea to do so to prevent problems down the road with someone putting one of these items into something like a `Dictionary`. The `List`'s contains method simply does a linear search calling `Equals` on each item in the `List` and the parameter. – Servy Jul 18 '12 at 16:58
  • According to MSDN, he should still override GetHashCode. Added a reference to my answer. – Eric J. Jul 18 '12 at 17:00
  • 1
    I only had two points to my comments. 1. Implementing `GetHashCode` is a good idea here, not a requirement. Yes, he *should* provide an appropriate implementation, but that's different than saying he *must*. 2. Your post implies that `List.Contains` uses `GetHashCode`. It does not. – Servy Jul 18 '12 at 17:03
  • Oh I see where you're coming from. I made a mental leap that lead to an incorrect statement. Two objects that are Equal should also have the same GetHashCode result (though of course not the other way around since two unequal object might happen to get the same hash code since there can be an infinite amount of unequal objects but there are only 2^32 possible hash codes). Amended the post. – Eric J. Jul 18 '12 at 17:17