3

I am currently trying to check if some list of mine contains an object. The list is a list of of an object which is made up of a struct which contain 2 fields.

I am trying to run this small code:

if(m_EatingMoves.Contains(i_Move))
{
  ....
}

But the expression will return false even though I can surely see on debug that the Move i want is inside the *m_EatingMove* list, I thought that the problem might be that I don't have an override for Equals in my struct so I found an implementation here on StackOverFlow, but the expression still returns false. Any Idea besides implementing my own Contains() ?

This is the struct:

    public struct Cell
    {
        public int Row;
        public int Col;

        public Cell(int i_Row, int i_Col)
        {
            this.Row = i_Row;
            this.Col = i_Col;
        }

        public override bool Equals(object obj)
        {
            if (!(obj is Cell))
                return false;

            Cell cell = (Cell)obj;
            return cell.Col == Col && cell.Row == Row;
        }
    }

Now I have another object which is made up of the above struct:

    public class Move
    {
        private Board.Cell m_Source;
        private Board.Cell m_Destination;

        public Move(Board.Cell i_Source, Board.Cell i_Destination)
        {
            m_Source = i_Source;
            m_Destination = i_Destination;
        }
....(Properties, etc..)

Finally we have the list which is initialized by the constructor

private List<Move> m_EatingMoves
Steinfeld
  • 649
  • 2
  • 10
  • 20

4 Answers4

3

You have to provide an override for GetHashCode() as well as Equals(). Either that, or implement IEquatable<T>.

The Contains method is a Linq extension, which uses the default equality comparer. From the docs:

The Default property checks whether type T implements the System.IEquatable interface and, if so, returns an EqualityComparer that uses that implementation. Otherwise, it returns an EqualityComparer that uses the overrides of Object.Equals and Object.GetHashCode provided by T.

McGarnagle
  • 101,349
  • 31
  • 229
  • 260
  • There's an actual member of the `List` class named `Contains`, which means the LINQ version shouldn't be considered. – Ben Voigt May 08 '13 at 01:19
3

You also need to override the GetHashCode method so that two cells that are equal return the same hash code. A pattern often used is to xor the hash codes of items being compared, e.g.:

public struct Cell
{
   [...]
   public override int GetHashCode()
   {
       return Row.GetHashCode() ^ Col.GetHashCode();
   }
}

Without overriding this method, data structures may not correctly compare for equality, causing the behavior you observed. The MSDN GetHashCode has additional documentation on how this method is used within the framework.

drf
  • 8,461
  • 32
  • 50
1

I would recommend instead of comparing objects/structs (kinda hardly predictable task with potential multiple side effects) to add sort of unique id to your objects using simple type (e.g. string) and to use Contains() based on that id. Moreover, struct is a value type, thus may causing some problem with boxing/unboxing (might be a case). Regards, AB

Alexander Bell
  • 7,842
  • 3
  • 26
  • 42
0

Generally, the the List<T>.Contains is the generic method comparing elements using the EqualityComparer<T>. In your case, it calls the Object.Equals, you could overwrite Object.Equals.

You could refer to MSDN List(T).Contains Method

terry
  • 1,569
  • 11
  • 19