私はかなり堅牢であると信じている GetHashCode の実装を持っていますが、正直なところ、私はそれをインターネットの奥深くから掘り起こしました。 ' または GetHashCode の「不適切な」実装です。
私は GetHashCode について StackOverflow で多くのことを読みました。NHibernate で Equals/GetHashCode を上書きする必要がある理由のサンプルはありますか? このスレッドはおそらく最良の情報源だと思いますが、それでも疑問に思いました。
次のエンティティと、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);
}
}
この実装で宣伝されている安全性チェックの量は、過剰に思えます。これを書いた人が私よりも多くの特殊なケースを理解していたと仮定すると、それは私に自信を与えますが、なぜこれほど多くの単純化された実装を見ているのか疑問に思います。
Equals メソッドがオーバーライドされたときに GetHashCode をオーバーライドすることが重要なのはなぜですか? これらのさまざまな実装をすべて見てください。以下は、シンプルでありながら高い評価を得ている実装です。
public override int GetHashCode()
{
return string.Format("{0}_{1}_{2}", prop1, prop2, prop3).GetHashCode();
}
この実装は、私が提供したものよりも優れていますか、それとも劣っていますか? なんで?
どちらも等しく有効ですか?GetHashCode を実装するときに従うべき標準の「ガイドライン」はありますか? 上記の実装に明らかな欠陥はありますか? GetHashCode の実装を検証するテスト ケースを作成するにはどうすればよいですか?