簡単なGetHashCode()の実装例とパフォーマンス比較

追記:Visual Studio 2017・ReSharperで自動生成できるので、もはや自動生成一択。

Generate C# Equals and GetHashCode Method Overrides - Visual Studio | Microsoft Docs

stackoverflow.com


stackoverflow.com

IEquatableを実装した時にGetHashCode()を自分で実装することになるが、(たぶん)悪くはない実装でかつ簡単確実な実装としてこの方法が使いやすいと考えている。 GetHashCode()は軽くあって欲しいのでパフォーマンス比較 *1 をした。基準としてValueTupleのGetHashCode()の内部実装を直接実装したパターンも計測した。

[Config(typeof(BenchmarkConfig))]
public class GetHashCodeBenchmark
{
private int m_value = 10;
private EmptyClass m_instance = new EmptyClass();
[Benchmark]
public int AnonymousType_GetHashCode()
{
return new { m_value, m_instance }.GetHashCode();
}
[Benchmark]
public int ValueTuple_GetHashCode()
{
return (m_value, m_instance).GetHashCode();
}
[Benchmark(Baseline = true)]
public int Combine_GetHashCode()
{
return Combine(m_value.GetHashCode(), m_instance.GetHashCode());
}
// https://github.com/dotnet/corefx/blob/master/src/Common/src/System/Numerics/Hashing/HashHelpers.cs
private static int Combine(int h1, int h2)
{
uint rol5 = ((uint)h1 << 5) | ((uint)h1 >> 27);
return ((int)rol5 + h1) ^ h2;
}
}
public class EmptyClass
{
}

Method Mean Error StdDev Scaled ScaledSD Gen 0 Allocated
AnonymousType_GetHashCode 23.264 ns 1.9239 ns 0.1087 ns 6.18 0.02 0.0051 16 B
ValueTuple_GetHashCode 15.350 ns 0.1826 ns 0.0103 ns 4.08 0.00 - 0 B
Combine_GetHashCode 3.764 ns 0.0444 ns 0.0025 ns 1.00 0.00 - 0 B
  • 匿名型だとヒープにメモリ確保している=GCのお世話になる
  • ValueTupleだとスタックで事足りている=GCのお世話にならない
  • 直書きだととても速い

ValueTuple使うか直書きするかになるが、覚えやすさ・読みやすさ・間違えにくさを考えてValueTupleが使いやすいだろう。このアルゴリズムはModified Bernsteinというらしい*2