C# HashSet未调用重写的Equals方法
我有一个名为“x”的类,它覆盖了Equals(),如下所示:C# HashSet未调用重写的Equals方法,c#,C#,我有一个名为“x”的类,它覆盖了Equals(),如下所示: public override bool Equals(object obj) { if(obj is x) { return ((obj as x).key == this.key); } return false; } x SearchKey = new x(key); 当以下扩展方法尝试使用上述重写进行比较时,将不
public override bool Equals(object obj)
{
if(obj is x)
{
return ((obj as x).key == this.key);
}
return false;
}
x SearchKey = new x(key);
当以下扩展方法尝试使用上述重写进行比较时,将不使用Equals()
public static bool Contains(this HashSet<x> set, char key)
{
x SearchKey = new x(key);
return set.Contains(SearchKey);
}
你能解释一下这种行为吗
我原以为,Equals()将针对x本身的实例被调用,因为它是对象的子集。我错过了什么 您可能必须重写GetHashCode;)
在hashSet中,比较方法是hashcode 首先也是最重要的,正如其他人所指出的,您还必须重写
GetHashCode
。比如:
public override int GetHashCode()
{
return key.GetHashCode();
}
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();
}
您还必须实现
IEquatable
。集合转到IEquatable接口进行比较,该接口是类型安全的,在比较值类型时不会导致装箱/取消装箱
如前所述,您也应该重写GetHashCode
。
如果您使用的是像resharper这样的产品,该工具可以自动为您生成。一种常见的模式是:
public override int GetHashCode()
{
return key.GetHashCode();
}
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(object)仅检查类型不变条件,然后强制转换并重定向到接口方法
有关生成哈希代码的一般最佳实践,请参见John Skeets的答案。您还需要重写
GetHashCode
。您将同一行写了两次x SearchKey=new x(key)代码>在问题中。您所做的哪些更改使其工作?正如其他人所提到的,您始终需要重写GetHashCode
和Equals
方法。注意Add
和Contains
方法首先调用GetHashCode
方法,只有当返回的哈希代码在哈希集中不存在时才会调用Equals
方法。不,在哈希集中,第一个比较方法是按哈希代码,但这不是“比较方法”。如果多个不同的项具有相同的哈希代码,哈希集将不会将它们视为相等,它仍会调用Equals
记住哈希代码
可能会发生冲突。此答案不完整HashSet
中的Contains方法具有不同的签名。我想他的扩展方法会被正确调用。我验证了…我的扩展方法called@KrisVandermotten你说得对,我会更新我的答案!阿迪斯是对的。只要扩展方法具有与在类型上声明的方法不同的签名,就会调用它。只有当扩展名具有完全相同的签名时,types方法才优先。@Zebi right。一开始我看错了签名:)很好的提示,谢谢!我认为R#这样做在这两种情况下都是安全的,但如果你手动这样做,这样做会更简单。+1,但你不必在非泛型Equals
方法中进行这些引用检查。只是返回等于(obj作为实体)
将用于类,如果(!(obj是实体))返回false,则将返回false;回报等于((实体)obj)代码>对于结构(对于结构,您无论如何也不需要在泛型Equals
方法中进行引用检查)。。