覆盖 GetHashCode [重复]

Posted

技术标签:

【中文标题】覆盖 GetHashCode [重复]【英文标题】:Overriding GetHashCode [duplicate] 【发布时间】:2011-05-13 12:46:30 【问题描述】:

如您所知,GetHashCode 返回一个半唯一值,可用于标识集合中的对象实例。作为一种好的做法,建议重写此方法并实现您自己的方法。

我的问题是 - 您在处理自定义对象时会覆盖此方法吗?如果是这样,您使用什么算法来生成唯一 ID?

我正在考虑生成一个 GUID,然后从该标识符获取整数数据。

【问题讨论】:

阅读this question 及其答案。它概述了一个好的哈希码实现。对于可变对象 here 覆盖 GetHashCode 也有很好的讨论。 我不知道“半唯一”是什么意思......一个值要么是唯一的,要么不是,而且哈希码不是唯一的。因此,它不允许您识别列表中的对象。覆盖GetHashCode 不是“一个好习惯”,这是您需要 时要做的事情(例如,将对象用作字典中的键),而不是因为您认为这是一个好习惯练习。 使用对象作为键可以被认为是识别集合中的对象——这正是我寻找关于什么是构建标识符的最佳算法的输入的原因。截至半唯一 ID:west-wind.com/Weblog/posts/4741.aspx 丹尼斯,你首先需要考虑你想要什么样的平等行为。对于默认的引用相等(对于具有标识的可变对象),您无需执行任何操作。 【参考方案1】:

如果您使用 resharper,它可以为您生成 GetHashCode()、Equals 和运算符方法体。

Alt+Insert 访问此菜单。

http://www.jetbrains.com/resharper/webhelp/Code_Generation__Equality_Members.html

【讨论】:

【参考方案2】:

当您覆盖GetHashCode() 时,您还需要覆盖Equals()operator==operator!=。并且要非常小心地满足这些方法的所有要求。

指南是here on MSDN。最重要的一句话:

在可变类型中覆盖 operator == 不是一个好主意。

【讨论】:

据我了解,这没有任何意义,因为对象不会改变它的状态。 什么没有意义? 字符串是不可变的,你没用过name == "x" 吗? 是的,但是当你修改一个字符串时,你会创建一个新对象(例如当你使用替换时)。 关键是,在重新分配变量之前,依靠 == 保持真实是很自然的;让突变副作用改变 == 过去的含义并不直观,因为默认情况下支持比较运算符的任何东西都是值类型或不可变的。这些仅在您说 var = "new value" 时才更改值,这明确暗示先前的 == 可能不再正确。引用类型可以从其他代码中改变状态,而在其他地方改变对象的方法可以改变相等性。 Equals 不提供相同的期望,因为它是一个方法定义,而不是语法。【参考方案3】:

在我个人的使用中,我也只在覆盖 equals 方法时覆盖。通常,我会为我知道可能会对其运行 LINQ to Objects 查询或其他一些比较操作的对象执行此操作。

如果说 LINQ to SQL 实体或 DTO 对象,我通常会返回主键值。无论返回什么,如果不将值存储在本地,可能会产生意想不到的结果。

HTH。

【讨论】:

【参考方案4】:

我通常会覆盖数据类(即值语义有意义的类)的哈希码和相等检查方法。查看this question 以获得常见的实现。如果您确实覆盖哈希码覆盖等于。使用 GUID 是一个非常糟糕的主意,因为您希望两个不同实例但具有相同 的对象具有相同的哈希码,并且等于返回 true。

【讨论】:

【参考方案5】:

您只需要在覆盖 Equals 时覆盖 GetHashCode。默认的 GetHashCode 由运行时以您想要的类似方式实现 - 每个对象都有一个由运行时分配的隐藏字段。

How to override GetHashCode

实际上,您的 IDE 应该为您执行此操作 - 当您键入“override GetHashCode”时,IDE 应该生成此样板代码。 Visual Studio 不这样做,但 SharpDevelop 会。

【讨论】:

GetHashCode 方法的默认实现不保证不同对象的返回值唯一。因此,此方法的默认实现不得用作散列目的的唯一对象标识符。来自:msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx 在 VS 中必须使用 equals sn-p 代替 @brain - 我读过这个。这是否意味着当您想将对象存储在字典中时,您应该始终覆盖 GetHashCode?我不这么认为——几乎没有人这样做。对于 Dictionary 的目的,默认实现可以正常工作。它并不完美,但很好:***.com/questions/750947/net-unique-object-identifier【参考方案6】:

通常我使用类的组件属性中聚合的 GetHashCode。例如

public class Test

  public string Text  get; set; 
  public int Age  get; set; 

  public override GetHashCode()
  
    int result = 
      string.IsNullOrEmpty(Text) ? 0 : Text.GetHashCode()
      + Age.GetHashCode();

    return result;
  

【讨论】:

这不是一个很好的方法,请参阅***.com/questions/263400/… 一般来说,添加不利于创建复合哈希码。但在这个具体的例子中,我认为它没有问题。但当然,不覆盖 Equals 的覆盖 GetHashCode 没有多大意义。 嗯,你每天都能学到一些东西!

以上是关于覆盖 GetHashCode [重复]的主要内容,如果未能解决你的问题,请参考以下文章

正确实施 GetHashCode [重复]

自定义类型 GetHashCode [重复]

如果在覆盖 Equals() 时未能覆盖 GetHashCode(),会出现啥问题? [复制]

未调用 C#GetHashCode/Equals 覆盖

如何在没有任何数字作为字段的情况下覆盖 GetHashCode()?

为啥 ReSharper GetHashCode 覆盖使用“397”?