我有一个继承自B类并实现IEqualityComparer<A>
的A类。
这意味着A类提供了自己的Equals和GetHashCode方法实现。到现在为止还挺好。
问题是我不明白为什么代码的行为方式如下:
调试器将只到达A的Equals实现断点
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
}
}
答案 0 :(得分:1)
实施IEqualityComparer<T>
并非override
GetHashCode
和Equals
的基本实施。
实现IEqualityComparer<T>
允许您将实现者的实例作为T
的相等比较器提供。这是几个linq扩展和泛型集合构造函数的通用参数。
覆盖Equals
和GetHashCode
影响类的实例测试相等的方式。利用调用Equals
和GetHashCode
的其他说明,例如基本=
和!=
运算符以及linq扩展和通用集合构造函数,其中您不提供替代IEqualityComparer<T>
和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);
}
}
1}}。
这些概念类似但用于不同目的,它们不是部分可互换的。
让我展开一个例子,
A
Equals
的此实现正确覆盖GetHashCode
和var distinct = aSequneceOfA.Distinct();
,此更改足以确保在调用linq扩展后
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());
,
A
不同的ingnores Equals
的重载被覆盖GetHashCode
和AComparerInsensitive
并使用{{1}}来执行比较。
答案 1 :(得分:1)
听起来你使用的是错误的界面。 IEqualityComparer<>
通常用于比较 其他 类型实例的类。
您的类型应该只是实现IEquatable<A>
和覆盖Equals(object)
和GetHashCode()
。请注意签名。
像这样:
public class A : B, IEquatable<A>
{
public bool Equals(A other)
{
if (other == null || GetType() != other.GetType())
return false;
//your implementation
}
public override bool Equals(object obj)
{
return Equals(obj as A);
}
public override int GetHashCode()
{
//your implementation
}
}
然后您可以执行someEnumerableOfA.Distinct()
之类的操作,Linq方法将使用您的实现。
另一种选择是:
public class A : B // no interfaces
{
}
public class AEqualComparer : IEqualityComparer<A>
{
public bool Equals(A x, A y)
{
//your implementation
}
public int GetHashCode(A x)
{
//your implementation
}
}
使用其他选项,您需要someEnumerableOfA.Distinct(new AEqualComparer ())
。