GetHashCode不保证它返回的值/数字的唯一性

时间:2012-09-29 01:22:10

标签: c# .net

我正在开发一个简单的2D环境,并绘制每个对象,例如line,rectangle和...通过调用GetHashCode()

获取唯一的id

现在,我注意到MSDN page它并不保证其结果是唯一的:

GetHashCode方法的默认实现不保证不同对象的唯一返回值。此外,.NET Framework不保证GetHashCode方法的默认实现,并且它返回的值在不同版本的.NET Framework之间是相同的。因此,不得将此方法的默认实现用作散列目的的唯一对象标识符。

现在,问题是除GetHashCode()方法之外还存在哪些其他选项?

谢谢, 阿米特

4 个答案:

答案 0 :(得分:3)

也许最好完全放弃哈希码? GetHashCode非常适合快速简便的修复,但如果您需要对象的真实ID,那么您应该创建真实的ID。像32/64位自动递增整数这样的东西可能很多。

虽然哈希代码的冲突率与哈希的长度相关联,但仍然无法保证在发生冲突之前达到可能的最大哈希值。如果您自己管理ID,则可以提前计划以获得足够的ID。

另外 - 您对框架版本之间的GetHashCode()的评论不同。我只能想象,如果您将哈希值保存到某种保存文件中,然后尝试重新加载它们,发现它们与正在运行的程序的哈希值不匹配,因为它们已保存,这在您的情况下会很重要通过不同版本的框架。如果是这种情况,我会建议您自己在对象上创建和管理ID。

答案 1 :(得分:3)

您需要生成自己的唯一ID

如果对象具有自然键,有时可以从对象属性派生唯一ID 如果对象没有自然键,则必须生成唯一ID,并且通常将唯一ID传递给构造函数中的对象。

GetHashCode是唯一的ID,因为它不能保证是唯一的 .NET内部不使用GetHashCode来实现唯一性 .NET内部使用GetHashCode加速相等比较和HashBuckets。

如果您要生成自己的唯一ID,则应覆盖GetHashCode和Equals 这样.NET就可以使用您的唯一标识符进行相等比较。

.NET GetHashCode()不是必需的,也不保证是唯一的 .NET GetHashCode()不仅限于Int32 .NET GetHashCode()是Int32。

如果GetHashCode不相等,则两个对象不相等 如果GetHashCode相等,那么两个对象可能相等也可能不相等。 等于是平局 为了速度,首先比较GetHashCode。 GetHashCode也用于hashbuckets,以提高集合速度,如HashSet和Dictionary。

如果散列是唯一的,那么它被认为是一个完美的散列。

经典示例

class Point: object 
{
   protected int x, y;

   public Point(int xValue, int yValue)
   {
        x = xValue;
        y = yValue;
   }
   public override bool Equals(Object obj) 
   {
      // Check for null values and compare run-time types.
      if (obj == null || GetType() != obj.GetType()) 
         return false;

      Point p = (Point)obj;
      return (x == p.x) && (y == p.y);
   }
   public override int GetHashCode() 
   {
      return x ^ y;
   }
}

由于Point具有Int32 X Int32可能的值,因此很明显它不能用单个Int32唯一标识。 仍然GetHashCode是有价值和必需的。只有1 / Int32的机会需要更昂贵的Equals,并且GetHashCode用于散列桶。

考虑简单点

class Point: object 
{
   protected byte x, y;

   public Point(byte xValue, byte yValue)
   {
        x = xValue;
        y = yValue;
   }
   public override bool Equals(Object obj) 
   {
      // Check for null values and compare run-time types.
      if (obj == null || GetType() != obj.GetType()) 
         return false;

      Point p = (Point)obj;
      return (x == p.x) && (y == p.y);
   }
   public override int GetHashCode() 
   {
      return (x * 256) + y;
   }
}

在这个简单的点上,GetHashCode将唯一地标识该对象。 你无法覆盖其中一个。必须覆盖两者或两者。

答案 2 :(得分:2)

这取决于您使用的唯一ID。这听起来像是用于识别对象实例,这可能意味着哈希代码不是您想要的。

如果两个对象是彼此的.Equals(),它们应该具有相同的哈希码,但正如您所发现的,反之则不正确(具有相同的哈希码并不意味着它们是.Equals( ))。

您需要什么独特的身份证?如果您没有使用哈希码将对象放入查找中,那么最好为它们分配一个像Guid(var uniqueId = Guid.NewGuid())这样的唯一ID。

答案 3 :(得分:1)

没有散列函数可以保证返回值的唯一性。

这取决于碰撞概率有多小。

GetHashCode()返回一个32位整数,这可能不足以假设唯一性。 考虑其他算法,如SHA-1,SHA-2,其哈希长度更长,冲突概率远低于32位整数。