简体   繁体   中英

C# Using Equals method in a generic list fails

I have a project where I have class State which uses templates. I have a class Cell, and I use it as State, so State holds a Cell as genericState. Now I have a generic function which checks if two instances are equal. Problem is, it never leaves the State Equals method to Cell Equals method.

public class State<T>
{
    public T genericState;  //in my case T is a cell
    public State(T cellState) // CTOR
    {
        this.genericState = cellState;  
    }

    public override bool Equals(object obj)
    {            
        return genericState.Equals((obj as State<T>).genericState); 
    } //never leaves
}

and code of Class Cell, in which it never gets:

public class Cell
{
    public int row, col;
    public bool visited;
    public char value;
    public bool Equals(Cell other)   //never gets here
    {            
       return other != null && other.row == row && other.col == col;    
    }
 }

I don't understand why it never gets to Equal method of Cell. What could be wrong with the code?

The problem is that your code does not know that T has a special method

bool Equals<T>(T other)

It thinks that it should be calling Cell 's override of Equals(object) , which your code does not override.

Fixing this is simple: add IEquatable<Cell> to the list of interfaces implemented by Cell , and add a constraint on T to ensure that it implements IEquatable<T> :

public class State<T> where T : IEquatable<T> {
    ... // The rest of the code remains the same
}
...
public class Cell : IEquatable<Cell> {
    ... // The rest of the code remains the same
}

Firstly, you should override object.Equals to defer to this Equals :

public override bool Equals(object obj) => Equals(obj as Cell);

And if you are overriding object.Equals then you also need to override object.GetHashCode() :

public override int GetHashCode() => row * 31 + col;

Further to this, for better performance you could have Cell implement IEquatable<Cell> , and in your State<T>.Equals use EqualityComparer<T>.Default . This will be better because EqualityComparer<T>.Default uses IEquatable<T>.Equals(T) when implemented, falling back to object.Equals(object) when that isn't available.

genericState.Equals is the equality method derived from object . In your Cell class, you are not overriding object.Equals(object) , so your equality method ( Cell.Equals(Cell) ) is not being called, but instead, Cell.Equals(object) is being called. So what you can do to fix this is change your Cell class to override the default equality method:

public class Cell
{
    public int row, col;
    public bool visited;
    public char value;
    public override bool Equals(object other)   //never gets here
    {            
       if(!(other is Cell)) return false;
       return other != null && other.row == row && other.col == col;    
    }
 }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM