【发布时间】:2013-07-06 05:28:47
【问题描述】:
我有一个 GetHashCode 的实现,我认为它相当健壮,但老实说,我是从互联网深处挖掘出来的,虽然我理解所写的内容,但我觉得没有资格将其描述为GetHashCode 的“好”或“坏”实现。
我在 StackOverflow 上阅读了大量有关 GetHashCode 的内容。 Is there a sample why Equals/GetHashCode should be overwritten in NHibernate? 我认为这个帖子可能是最好的信息来源,但它仍然让我感到疑惑。
考虑以下实体及其给定的 Equals 和 GetHashCode 实现:
public class Playlist : IAbstractDomainEntity
{
public Guid Id { get; set; }
public string Title { get; set;
public Stream Stream { get; set; }
// Use interfaces so NHibernate can inject with its own collection implementation.
public IList<PlaylistItem> Items { get; set; }
public PlaylistItem FirstItem { get; set; }
public Playlist NextPlaylist { get; set; }
public Playlist PreviousPlaylist { get; set; }
private int? _oldHashCode;
public override int GetHashCode()
{
// Once we have a hash code we'll never change it
if (_oldHashCode.HasValue)
return _oldHashCode.Value;
bool thisIsTransient = Equals(Id, Guid.Empty);
// When this instance is transient, we use the base GetHashCode()
// and remember it, so an instance can NEVER change its hash code.
if (thisIsTransient)
{
_oldHashCode = base.GetHashCode();
return _oldHashCode.Value;
}
return Id.GetHashCode();
}
public override bool Equals(object obj)
{
Playlist other = obj as Playlist;
if (other == null)
return false;
// handle the case of comparing two NEW objects
bool otherIsTransient = Equals(other.Id, Guid.Empty);
bool thisIsTransient = Equals(Id, Guid.Empty);
if (otherIsTransient && thisIsTransient)
return ReferenceEquals(other, this);
return other.Id.Equals(Id);
}
}
在这个实现中吹捧的安全检查数量似乎超过了顶部。它激发了我的信心——假设写这篇文章的人比我理解更多的极端案例——但也让我想知道为什么我看到这么多简单的实现。
Why is it important to override GetHashCode when Equals method is overridden? 看看所有这些不同的实现。下面是一个简单但评价很高的实现:
public override int GetHashCode()
{
return string.Format("{0}_{1}_{2}", prop1, prop2, prop3).GetHashCode();
}
这个实现会比我提供的更好还是更差?为什么?
两者是否同样有效?实施 GetHashCode 时是否应遵循标准“指南”?上面的实现有什么明显的缺陷吗?如何创建测试用例来验证 GetHashCode 的实现?
【问题讨论】:
-
我总是在这里接受的答案中使用 Jon Skeet 的建议:stackoverflow.com/questions/263400/…
-
您已经遇到了麻烦,因为您有效地使用了一个可变值进行散列。如果项目在存储在任何使用散列的容器中时被修改,这很糟糕。你最终会得到一个损坏的容器。
-
您的 Id 属性是可变的。我可以将它存储在一个哈希集中,更改它的 ID,然后毫无怨言地存储一个“重复”条目。这违反了设计准则。
-
Jon 提倡的实现不是基于一定数量的属性;这只是一个例子。请记住,GetHashCode() 用于允许将类的实例用作集合中的键,例如字典或哈希表。因此,一个健壮的实现将考虑那些因实例而异的字段,这些字段通常是一个类中的所有字段。在他的示例中,这是 3 个字段;在你的,它看起来像 1。
-
@StriplingWarrior 你知道.. 我真的不确定。我想它可能会在 Session 中存储两个副本,直到调用 Commit 并且如果两者仍然存在,如果违反约束,则会引发异常。
标签: c# equals gethashcode