为此结构实现GetHashCode的正确方法

Mik*_*sen 12 .net c# hash

我想使用日期范围(从一个日期到另一个日期)作为字典的键,所以我编写了自己的结构:

   struct DateRange
   {
      public DateTime Start;
      public DateTime End;

      public DateRange(DateTime start, DateTime end)
      {
         Start = start.Date;
         End = end.Date;
      }

      public override int GetHashCode()
      {
         // ???
      }
   }
Run Code Online (Sandbox Code Playgroud)

实现GetHashCode的最佳方法是什么,所以没有两个不同范围的对象会生成相同的哈希?我希望哈希冲突尽可能不可能,虽然我理解Dictionary <>仍将检查我将实现的相等运算符,但不想过多地污染示例代码.谢谢!

Mar*_*ers 20

作为乔恩斯基特表明您可以使用从有效的Java方法在这里.对于您的特定类型:

public override int GetHashCode()
{
    unchecked // Overflow is fine, just wrap
    {
        int hash = 17;
        hash = hash * 23 + Start.GetHashCode();
        hash = hash * 23 + End.GetHashCode();
        return hash;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 你能解释一下,为什么你用17和23? (4认同)
  • @Martin 与素数相乘的好处在哪里? (2认同)

Vis*_*ean 8

不是为了复活死者,而是我来这里是为了寻找一些东西,对于较新的 C# 版本,你可以这样做

public override int GetHashCode()
{
    return HashCode.Combine(Start, End);
}
Run Code Online (Sandbox Code Playgroud)

目前可以在这里找到源: https: //github.com/dotnet/corert/blob/master/src/System.Private.CoreLib/shared/System/HashCode.cs

在我的初步测试中(使用 Jon Skeets 微基准测试框架),就性能而言,它似乎与公认的答案非常相似,即使不一样。

  • 我查了一下。经过 10000000 次运行后,结果似乎非常相似。 (2认同)

l33*_*33t 7

在C# 7你可以这样做:

public override int GetHashCode() => (Start, End).GetHashCode();
Run Code Online (Sandbox Code Playgroud)

该ValueTuple是可用的.NET Framework 4.7和.NET Core,或通过的NuGet。

不确定它的性能如何,但如果任何自定义代码能打败它,我会感到惊讶。

  • 我不确定这个解决方案有多新,但是当我尝试时,Visual Studio 给了我一个“System.HashCode.Combine(Start, End)”的代码提示。 (2认同)
  • 注意:System.HashCode仅在.Net Core中可用 (2认同)

The*_*Jan 5

我相信微软在元组中实现GetHashCode()并使用这样的东西而没有任何愚蠢的魔法:

public override int GetHashCode()
{
    Tuple.Create(x, y).GetHashCode();
}
Run Code Online (Sandbox Code Playgroud)

  • 没有!!您绝对不能在GetHashCode()中创建堆对象。此代码最终将破坏应用程序性能。 (3认同)