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)
它认为它应该调用 Cell
对 Equals(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)
。
我有一个项目,其中 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)
它认为它应该调用 Cell
对 Equals(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)
。