我有一个名为"x"的类,它覆盖了 Equals(),如下所示:
public override bool Equals(object obj)
{
if(obj is x)
{
return ((obj as x).key == this.key);
}
return false;
}
当以下扩展方法尝试使用上述覆盖进行比较时,不会使用 Equals():
public static bool Contains(this HashSet<x> set, char key)
{
x SearchKey = new x(key);
return set.Contains(SearchKey);
}
仅当我修改 extensio 方法中的第一行时,我才会获得预期的行为,如下所示:
x SearchKey = new x(key);
你能解释一下这种行为吗?
我原以为 Equals() 会对 x 本身的实例进行调用,因为它是 Object 的一个子集。我错过了什么?
首先,正如其他人指出的那样,您还必须覆盖GetHashCode
。像这样:
public override int GetHashCode()
{
return key.GetHashCode();
}
也必须实现IEquatable<T>
。集合转到 IEquatable 接口进行比较,该接口是类型安全的,在比较值类型时不会导致装箱/取消装箱。
如前所述,您也应该覆盖GetHashCode
。如果您使用的是像 resharper 这样的产品,该工具可以为您自动生成此内容。常见的模式如下所示:
public virtual bool Equals(Entity other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return other.Id.Equals(Id);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (!(obj is Entity)) return false;
return Equals((Entity)obj);
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
在这里,您使用接口方法执行所有基于类型的内容,并使用被覆盖的 Equals(对象) 仅检查类型不变条件,然后强制转换并重定向到接口方法。
有关生成哈希代码的一般最佳实践,请参阅此处的 John Skeets 答案。
您可能需要覆盖 GetHashCode ;)在哈希集中,比较方法是哈希码。