- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
在 .NET 中,GetHashCode
method在整个 .NET 基类库中的很多地方都有使用。正确实现它对于在集合中快速查找项目或确定相等性尤为重要。
是否有关于如何为我的自定义类实现 GetHashCode
的标准算法或最佳实践,这样我就不会降低性能?
最佳答案
我通常采用类似 Josh Bloch 的fabulous Effective Java 中给出的实现方式.它速度很快,并且创建了一个不太可能导致冲突的非常好的散列。选择两个不同的质数,例如17 和 23,然后做:
public override int GetHashCode()
{
unchecked // Overflow is fine, just wrap
{
int hash = 17;
// Suitable nullity checks etc, of course :)
hash = hash * 23 + field1.GetHashCode();
hash = hash * 23 + field2.GetHashCode();
hash = hash * 23 + field3.GetHashCode();
return hash;
}
}
如评论中所述,您可能会发现最好选择一个大质数作为乘数。显然 486187739 很好......虽然我见过的大多数小数字示例都倾向于使用素数,但至少有类似的算法经常使用非素数。在不完全- FNV稍后举例,例如,我使用的数字显然效果很好——但初始值不是质数。 (乘法常数 是 质数。我不知道它有多重要。)
这优于 XOR
哈希码的常见做法,主要有两个原因。假设我们有一个包含两个 int
字段的类型:
XorHash(x, x) == XorHash(y, y) == 0 for all x, y
XorHash(x, y) == XorHash(y, x) for all x, y
顺便说一句,早期的算法是 C# 编译器当前用于匿名类型的算法。
This page提供了很多选择。我认为在大多数情况下,上述内容“足够好”并且非常容易记住和正确。 FNV alternative 同样简单,但使用不同的常量和 XOR
而不是 ADD
作为组合操作。它看起来有点像下面的代码,但正常的 FNV 算法对单个字节进行操作,因此这需要修改为每个字节执行一次迭代,而不是每个 32 位哈希值。 FNV 也是为可变长度的数据而设计的,而我们在这里使用它的方式总是针对相同数量的字段值。对此答案的评论表明,此处的代码实际上(在测试的示例案例中)不如上面的添加方法有效。
// Note: Not quite FNV!
public override int GetHashCode()
{
unchecked // Overflow is fine, just wrap
{
int hash = (int) 2166136261;
// Suitable nullity checks etc, of course :)
hash = (hash * 16777619) ^ field1.GetHashCode();
hash = (hash * 16777619) ^ field2.GetHashCode();
hash = (hash * 16777619) ^ field3.GetHashCode();
return hash;
}
}
请注意,需要注意的一件事是,理想情况下,您应该防止在将相等性敏感(因此哈希码敏感)状态添加到依赖于哈希码的集合后发生更改。
根据 documentation :
You can override GetHashCode for immutable reference types. In general, for mutable reference types, you should override GetHashCode only if:
- You can compute the hash code from fields that are not mutable; or
- You can ensure that the hash code of a mutable object does not change while the object is contained in a collection that relies on its hash code.
FNV 的链接文章已损坏,但互联网文件馆中有一份副本:Eternally Confuzzled - The Art of Hashing
关于.net - 覆盖 GetHashCode 的最佳算法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54366848/
我有一个实现 IEquatable<> 的类 A,使用它的字段(比如 A.b 和 A.c)来实现/覆盖 Equals() 并覆盖 GetHashCode(),并且一切正常,99% 的时间。 A 类是继
为什么会这样17m.GetHashCode() == 17d.GetHashCode()(m =十进制,d =两倍) 此外,如预期的那样17f.GetHashCode() != 17d.GetHash
我找到了一个 GetHashCode() 的实现,看起来像这样 Guid _hashCode = Guid.NewGuid(); public override int GetHash
我想使用 Distinct()使用我的数据,声明为 IEnumerable> .在这种情况下,我必须实现自己的 IEqualityComparer还有我的问题: 以下实现之间有什么区别吗? publi
我认为这些集合的 GetHashCode 函数不将它们的哈希码基于列表中的项目是很奇怪的。 我需要它来工作以提供脏检查(您有未保存的数据)。我已经编写了一个覆盖 GetHashCode 方法的包装类,
明明有更好的hash方法 有位朋友对我吐槽前几天我列举的在源生成器的生成db映射实体的优化点 提前生成部分 hashcode 进行比较 所示代码 public static void Gener
我正在为在 .net 上运行的语言编写编译器,我希望它做的一件事是自动生成 GetHashCode 方法,但我有几个问题: 这是否可能,编译器是否足够了解所涉及的类型以合理地实现该方法? 我应该为值类
昨天我浏览了一些 .net 源代码,看到了一些 GetHashcode 的实现,其中包含以下内容: (i1 << 5) + i ^ i2 我了解代码在做什么以及为什么。我想知道的是他们为什么使用 (i
对于 Delphi 项目(使用 RAD Studio XE7 构建),我想创建一个画笔字典。每个字典项都包含一个 TMyBrush 对象作为键,该对象描述要检索的画笔,以及一个 GDI+ 画笔作为值。
我有以下类(class): public class Foo { int year; string name; int category; } 这是一些示
我有这个问题。 public class Foo : object { public override bool Equals(obj a, objb) { return
有时我需要没有字段(消息头、模式等)的值对象,例如: abstract class RequestHeader { } sealed class FirstRequestHeader : Reques
我正在使用 Linq-to-Sql 查询 SQL Server 数据库。此查询返回我的数据库中实体的列表。我的基础数据没有改变。 收到列表后,我会对其调用 GetHashCode 以测试是否相等。奇怪
我在这里阅读了一些与 GetHashCode 正确实现相关的问题。我没有找到的是什么时候我应该实现这个方法。 在我的具体案例中,我构建了一个简单的不可变结构: public struct MyStru
我正在使用 unity,而 unity 中没有元组,所以我创建了自己的元组类来工作,因为我的字典需要它。 Dictionary , Tile> 我创建的 Tile 类与解决这个问题并不相关(至少我认为
我在 Microsoft 文档中找到了以下内容: Two objects that are equal return hash codes that are equal. However, the r
我试着关注 Guidelines来自 MSDN,也引用了 This great question但下面的行为似乎并不像预期的那样。 我试图表示类似于 FQN 的结构,其中就好像 P1 在 P2 之前列
我最近用几种不同的方式问过这个问题,但没有得到告诉我如何使用 的字典的答案。当我持有对更改的内容的引用时需要处理 T.GetHashCode() .出于此问题的目的,“状态”指的是在 Equals(
我有以下类(class) public class ResourceInfo { public string Id { get; set; } public string Url {
首先,我使用 GetHashCode算法描述,here .现在,想象以下(人为的)示例: class Foo { public Foo(int intValue, double doubleV
我是一名优秀的程序员,十分优秀!