简体   繁体   English

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

[英]C# Using Equals method in a generic list fails

I have a project where I have class State which uses templates. 我有一个项目,我有类State使用模板。 I have a class Cell, and I use it as State, so State holds a Cell as genericState. 我有一个类Cell,我用它作为State,所以State将一个Cell作为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. 问题是,它永远不会将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
}

and code of Class Cell, in which it never gets: Class Cell的代码,它永远不会得到:

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. 我不明白为什么它永远不会达到Cell的Equal方法。 What could be wrong with the code? 代码有什么问题?

The problem is that your code does not know that T has a special method 问题是你的代码不知道T有一个特殊的方法

bool Equals<T>(T other)

It thinks that it should be calling Cell 's override of Equals(object) , which your code does not override. 它认为它应该调用CellEquals(object)覆盖,你的代码不会覆盖它。

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> : 固定,这是简单的:添加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
}

Firstly, you should override object.Equals to defer to this Equals : 首先,您应该覆盖object.Equals以遵循此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() : 如果你要重写object.Equals ,那么你还需要重写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 . 除此之外,为了获得更好的性能,您可以让Cell实现IEquatable<Cell> ,并在您的State<T>.Equals使用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. 这样会更好,因为EqualityComparer<T>.Default在实现时使用IEquatable<T>.Equals(T) ,当它不可用时回IEquatable<T>.Equals(T) object.Equals(object)

genericState.Equals is the equality method derived from object . genericState.Equals是从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. 在您的Cell类中,您没有覆盖object.Equals(object) ,因此不会调用您的相等方法( Cell.Equals(Cell) ),而是调用Cell.Equals(object) So what you can do to fix this is change your Cell class to override the default equality method: 那么你可以做些什么来解决这个问题就是改变你的Cell类来覆盖默认的相等方法:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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