在实现自定义类实例比较时,我们应该覆盖Equals
和GetHashCode
属性吗?
在下面的代码中,我有一组类。课程A
由 ID
,课程B
- Code
进行比较。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
List<I> bars = new List<I>();
bars.Add(new A() { Id = 1, Code = "one A" });
bars.Add(new B() { Id = 1, Code = "one B" });
bars.Add(new A() { Id = 1, Code = "one A+" });
bars.Add(new B() { Id = 1, Code = "one B" }); // Code = "one B+"
var distictBars = bars.Distinct();
foreach (var item in distictBars)
{
Debug.WriteLine(item.Code);
}
}
}
interface I
{
string Code { get; set; }
}
class A : I, IEquatable<A>
{
public int Id { get; set; }
public string Code { get; set; }
public bool Equals(A other)
{
// this is the ??? comparison
return this.Id == other.Id;
//return this.Code == other.Code;
}
public override bool Equals(object obj)
{
if (obj is A)
return this.Equals(obj as A);
else
return object.ReferenceEquals(this, obj);
}
public override int GetHashCode()
{
// this is the wanted comparison
return this.Id;
}
}
class B : I, IEquatable<B>
{
public int Id { get; set; }
public string Code { get; set; }
public bool Equals(B other)
{
// this is the ??? comparison
return this.Id == other.Id;
}
public override bool Equals(object obj)
{
if (obj is B)
return this.Equals(obj as B);
else
return object.ReferenceEquals(this, obj);
}
public override int GetHashCode()
{
// this is the wanted comparison
return this.Code.GetHashCode();
}
}
}
输出结果为:
one A
one B
如果评论Code = "one B+"
输出为
one A
one B
one B+
现在我问问自己,如果这似乎对比较没有影响,我应该覆盖Equals
课程中的B
是什么?
GetHasCode()
是否足以胜任这种比较?
答案 0 :(得分:15)
以下是您需要了解Equals
和GetHashCode
之间关系的内容。
散列表使用散列码快速查找预期存在元素的“桶”。 如果元素位于两个不同的桶中,则假设它们不能相等。
这样做的结果是,为了确定唯一性,您应该查看哈希码作为快速否定检查:即,如果两个对象具有不同的哈希码,则它们是不相同(无论他们的Equals
方法返回什么)。
如果两个对象具有相同的哈希码,则它们将驻留在哈希表的同一个桶中。 然后将调用他们的Equals
方法来确定相等。
因此GetHashCode
必须为您希望被视为相等的两个对象返回相同的值。
答案 1 :(得分:6)
Distinct
方法将使用GetHashCode
方法确定项目之间的不等式,并使用Equals
方法确定相等性。
首先使用哈希码快速比较以确定哪些项目肯定不相等,即具有不同的哈希码,然后比较具有相同哈希码的项目以确定哪些项目真正相等。
在B
类的实现中,您对GetHashCode
和Equals
方法的实现不一致,因此比较将无法正常进行。您的两个B
对象具有不同的哈希码,因此它们不会相互比较。两个被认为相等的项也应该返回相同的哈希码。
如果某个类实现了IEquatable<T>
接口,则会使用Equals(T)
方法,否则会使用Equals(object)
方法。
答案 2 :(得分:5)
您始终需要一起覆盖和以及兼容的实现。哈希码匹配/不匹配意味着(分别)“可能相等”和“不相等”。哈希码 本身 并不表示相等。因此,在找到哈希码匹配(或用于创建值组)之后,仍会检查Equals
以确定匹配。
如果两人不同意,你可能永远找不到匹配。