给定以下类别
public class Foo
{
public int FooId { get; set; }
public string FooName { get; set; }
public override bool Equals(object obj)
{
Foo fooItem = obj as Foo;
if (fooItem == null)
{
return false;
}
return fooItem.FooId == this.FooId;
}
public override int GetHashCode()
{
// Which is preferred?
return base.GetHashCode();
//return this.FooId.GetHashCode();
}
}
我重写了Equals方法,因为Foo表示Foos表的一行。哪个是重写GetHashCode的首选方法?
为什么重写GetHashCode很重要?
通过重写Equals,您基本上表明您更了解如何比较给定类型的两个实例。
下面可以看到ReSharper如何为您编写GetHashCode()函数的示例。请注意,这段代码是由程序员调整的:
public override int GetHashCode()
{
unchecked
{
var result = 0;
result = (result * 397) ^ m_someVar1;
result = (result * 397) ^ m_someVar2;
result = (result * 397) ^ m_someVar3;
result = (result * 397) ^ m_someVar4;
return result;
}
}
正如您所看到的,它只是试图根据类中的所有字段猜测一个好的哈希代码,但如果您知道对象的域或值范围,您仍然可以提供一个更好的哈希代码。
这并不一定重要;这取决于集合的大小和性能要求,以及您的类是否将用于您可能不知道性能要求的库中。我经常知道我的集合大小不是很大,我的时间比创建一个完美的哈希代码所获得的几微秒的性能更有价值;所以(为了消除编译器发出的恼人警告)我只需使用:
public override int GetHashCode()
{
return base.GetHashCode();
}
(当然,我也可以使用#pragma关闭警告,但我更喜欢这种方式。)
当然,当你处于一个你确实需要表现的位置时,这里其他人提到的所有问题都适用。最重要的是,否则在从哈希集或字典中检索项目时会得到错误的结果:哈希码不能随对象的生存时间而变化(更准确地说,在需要哈希码的时间,例如在字典中作为关键字时):例如,以下内容是错误的,因为Value是公共的,因此可以在实例的生命周期内在类外部进行更改,因此不能将其用作哈希代码的基础:
class A
{
public int Value;
public override int GetHashCode()
{
return Value.GetHashCode(); //WRONG! Value is not constant during the instance's life time
}
}
另一方面,如果无法更改值,则可以使用:
class A
{
public readonly int Value;
public override int GetHashCode()
{
return Value.GetHashCode(); //OK Value is read-only and can't be changed during the instance's life time
}
}