C# 在泛型列表中使用 Equals 方法失败

C# Using Equals method in a generic list fails

我有一个项目,其中 class State 使用模板。 我有一个 class Cell,我将它用作 State,因此 State 将 Cell 作为 genericState。 现在我有一个通用函数来检查两个实例是否相等。 问题是,它永远不会将 State Equals 方法留给 Cell Equals 方法。

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
}

和 Class 单元格的代码,其中它永远不会获取:

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;    
    }
 }

我不明白为什么它永远不会到达 Cell 的 Equal 方法。代码可能有什么问题?

genericState.Equals是从object派生出来的相等方法。在您的 Cell class 中,您没有覆盖 object.Equals(object),因此您的相等方法 (Cell.Equals(Cell)) 没有被调用,而是被调用 Cell.Equals(object) .所以你可以做的是改变你的 Cell class 来覆盖默认的相等方法:

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;    
    }
 }

问题是你的代码不知道T有一个特殊的方法

bool Equals<T>(T other)

它认为它应该调用 CellEquals(object) 的覆盖,您的代码不会覆盖它。

解决这个问题很简单:将 IEquatable<Cell> 添加到 Cell 实现的接口列表中,并在 T 上添加约束以确保它实现 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
}

首先,您应该覆盖 object.Equals 以遵从此 Equals:

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

如果你要覆盖 object.Equals 那么你还需要覆盖 object.GetHashCode():

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

此外,为了获得更好的性能,您可以 Cell 实施 IEquatable<Cell>,并在 State<T>.Equals 中使用 EqualityComparer<T>.Default。这会更好,因为 EqualityComparer<T>.Default 在实施时使用 IEquatable<T>.Equals(T),当 object.Equals(object) 不可用时回退到 object.Equals(object)