IEqualityComparer实现中GetHashCode和Equals之间的关系是什么? [重复]
这个问题在这里已有答案:
-
Why is it important to override GetHashCode when Equals method is overridden? 12个答案
-
IEqualityComparer GetHashCode being called but Equals not 4个答案
我有一个继承自B类并实现 IEqualityComparer<A>
的A类 . 这意味着A类提供了自己的Equals和GetHashCode方法实现 . 到现在为止还挺好 . 问题是我不明白为什么代码的行为方式如下:
调试器只会到达A 's Equals implementation breakpoint if A'的GetHashCode实现返回 this.GetHashCode()
而不是 obj.GetHashCode()
,其中"obj"是GetHashCode签名定义的参数(在我的例子中是A类型的变量) .
直觉上,我认为我应该返回我收到的对象的哈希码,但这样做会使编译器忽略实例的Equals实现 .
为什么会这样?
代码演示:
public class A : B, IEqualityComparer<A>
{
public bool Equals(A x, A y)
{
//my implementation...
}
public int GetHashCode(A obj)
{
//return obj.GetHashCode(); -> this makes my Equals implementation above be ignored! Why?
return this.GetHashCode(); -> my Equals implementation is used
}
}
回答(2)
实现 IEqualityComparer<T>
不是 GetHashCode
和 Equals
的基本实现 .
实现 IEqualityComparer<T>
允许您将实现者的实例作为 T
的相等比较器提供 . 这是几个linq扩展和泛型集合构造函数的通用参数 .
覆盖 Equals
和 GetHashCode
会影响类的实例测试的相等性 . 利用调用 Equals
和 GetHashCode
的其他实现,如基本 =
和 !=
运算符以及linq扩展和泛型集合构造函数,其中您不提供替代 IEqualityComparer<T>
.
这些概念类似,但 serve different purposes, they are not partially interchangable .
让我展开一个例子,
public class A
{
public string Value1 { get; set; }
public int Value2 { get; set; }
public override int GetHashCode()
{
unchecked
{
int hash = 17;
hash = (hash * 23) +
StringComparer.Ordinal.GetHashCode(this.Value1);
hash = (hash * 23) + this.Value2;
return hash;
}
}
public override bool Equals(object obj)
{
var a = obj as A;
if (a == null)
{
return false;
}
if (a.Value2 != this.Value2)
{
return false;
}
return StringComparer.Ordinal.Equals(
a.Value1,
this.Value1);
}
}
这个 A
的实现正确覆盖了 Equals
和 GetHashCode
,这个改变足以确保在调用linq扩展后
var distinct = aSequneceOfA.Distinct();
distinct
将不包含具有相同 Value2
且通常可比较的 Value1
的任何实例 . 无需其他接口实现即可实现此目的 .
现在,假设在某些情况下我对 Value1
的这种序数比较不满意,或许我需要一些不区分大小写 . 我可能会实现一个新的相等比较器 .
public class AComparerInsensitive : IEqualityComparer<A>
{
public bool Equals(A x, A y)
{
if (x == null)
{
return y == null;
}
if (y == null)
{
return false;
}
if (x.Value2 != y.Value2)
{
return false;
}
return StringComparer.CurrentCultureIgnoreCase.Equals(
x.Value1,
y.Value1)
}
public int GetHashCode(A a)
{
if (a == null)
{
return 0;
}
unchecked
{
int hash = 17;
hash = (hash * 23) +
StringComparer.CurrentCultureIgnoreCase.GetHashCode(
a.Value1);
hash = (hash * 23) + a.Value2;
return hash;
}
}
}
这将允许我调用 Distinct
的替代重载,
var insensitivelyDistinct = aSequneceOfA.Distinct(
new AComparerInsensitive());
不同的ingnores A
的重载被覆盖 Equals
和 GetHashCode
并使用 AComparerInsensitive
来执行比较 .
2 years ago
听起来你使用的是错误的界面 .
IEqualityComparer<>
通常用于比较 other 类型实例的类 .您的类型应该只执行
IEquatable<A>
and overrideEquals(object)
和GetHashCode()
. 注意签名 .像这样:
然后你可以做像
someEnumerableOfA.Distinct()
这样的东西,Linq方法将使用你的实现 .另一种选择是:
有了这个其他选项,你需要
someEnumerableOfA.Distinct(new AEqualComparer ())
.