【发布时间】:2011-11-16 21:43:21
【问题描述】:
简短的问题:如何为已重新实现 GetHashCode() 的对象获取 object.GetHashCode() 值?
长篇大论: 所以我有大约十万个对象,每个对象共享许多(非编译时)公共字符串。常见的情况是如果值相等,它就是同一个实例。
知道了这一点,我想我宁愿使用标准的对象比较 (ReferenceEquals) 而不是完整的字符串比较 - 特别是在字典中经常查找这些内容时。
所以我声明了一个 class ReferenceEqualityComparer : IEqualityComparer 与 Dictionary<string, TValue> 一起使用,认为无论如何都有它是有用的,然后开始尝试实现这两种方法。
等于很简单,使用object.ReferenceEquals。
但是对于GetHashCode 方法,我如何获得object.GetHashCode() 的等效项?
我如何获得对象实例的一些表示?
我知道还有其他方法可以做到这一点 - 创建一个 InternedString 类,该类包含对 string 的引用,但不实现 Equals 或 GetHashCode,或者存储索引而不是字符串与每个对象,但我现在很好奇 - 实际上有没有办法实现一个通用的ReferenceEqualityComparer?
【问题讨论】:
-
Jon Skeet 对于如何做你正在做的事情,当然给出了简单而正确的答案。不过,我的倾向是将每个字符串包装在一个简单的不可变结构中,该结构简单地保存对字符串的引用并覆盖 GetHashCode 和 Equals 以在封闭的字符串上调用 RuntimeHelpers.GetHashCode 或 Object.ReferenceEquals。
-
我不喜欢将 ReferenceEquals 与 String 类型的暴露对象一起使用,因为很多代码会期望任何 String 对象都可以替换为具有相同长度和内容的任何其他对象,而不会影响程序语义。一个只包含一个类引用的值类型在大多数情况下应该非常像一个引用类型。我知道的最大问题是,如果转换为 Object 或接口类型,这种类型将被装箱。
-
嗨 supercat,这是一个选项是的。尽管如此,所有字符串都只在不可变的内部类中使用 - 不是公共的,并且没有被违反规则的字符串替换的危险。但是为了正确起见,我可能会遵循您的建议 - 但是昨天,在不了解 RuntimeHelpers 的情况下,我什至无法弄清楚如何做到这一点,默认的 struct.GetHashCode 非常慢。
-
Supercat,只是让您知道我确实听从了您的建议,使自己成为 InternedString 结构,并带有 InternedString.Pool 工厂类。需要考虑一个小问题,我决定在添加每个字符串时创建一个新字符串,纯粹是为了有一个规则,即来自不同池的两个 InternedString 永远不会比较相等,这可能会导致一些难以跟踪的错误。
-
默认结构 GetHashCode 和 Equals 会调用 String.GetHashCode 和 String.Equals——这不是您想要的。如果需要,您可以让每个结构都保存一个 Int64 序列号和字符串(在所有池的共享序列号上使用 Interlocked.Increment);结构的 GetHashcode 可以返回 Int64 的低位字,Equals 可以简单地比较 Int64 值而不考虑字符串内容。这将需要更多的结构空间,但避免任何需要防御性地复制字符串。
标签: c# hash dictionary iequalitycomparer