我有多个课程,由于某些原因,不遵循官方的 Equals 合同。在覆盖的 GetHashCode()中,这些类只返回0,因此可以在Hashmap中使用它们。

其中一些类实现了相同的接口,并且使用此接口作为密钥的Hashmaps。所以我认为每个类至少应该在 GetHashCode()中返回一个不同的(但仍然是常量的)。

问题是如何选择这个值。我应该简单地让第一堂课返回1,下一堂课2等等吗?或者我应该尝试像

这样的东西
class SomeClass : SomeInterface {
    public overwrite int GetHashCode() {
        return "SomeClass".GetHashCode();
    }
}

所以哈希分布更均匀? (我是否必须自己缓存返回的值,或者Microsoft的编译器能够优化它吗?)

更新:无法为每个对象返回单个哈希码,因为Equals违反了合同。特别是,我指的是这个问题

有帮助吗?

解决方案

在编写矢量类时遇到了这个问题。我想比较向量的相等性,但浮点运算给出舍入误差,所以我想要近似相等。除非你的实现是对称的,反身的和传递的,否则长话短说,最重要的等于是一个坏主意。

其他类将假设equals具有这些属性,使用这些类的类也是如此,因此您可能会遇到奇怪的情况。例如,列表可能会强制执行唯一性,但最终会得到两个元素,这两个元素的值等于某个元素B.

当您打破相等时,哈希表是不可预测行为的完美示例。例如:

//Assume a == b, b == c, but a != c
var T = new Dictionary<YourType, int>()
T[a] = 0
T[c] = 1
return T[b] //0 or 1? who knows!

另一个例子是Set:

//Assume a == b, b == c, but a != c
var T = new HashSet<YourType>()
T.Add(a)
T.Add(c)
if (T.contains(b)) then T.remove(b)
//surely T can't contain b anymore! I sure hope no one breaks the properties of equality!
if (T.contains(b)) then throw new Exception()

我建议使用另一种方法,名称为ApproxEquals。您可能还会考虑重写==运算符,因为它不是虚拟的,因此不会被其他类意外地使用,例如Equals可能。

如果你真的不能使用哈希表的引用相等性,不要破坏你可以使用的情况的性能。添加一个IApproxEquals接口,在您的类中实现它,并将一个扩展方法GetApprox添加到Dictionary,它枚举查找大致相等的键的键,并返回相关的值。您还可以编写自定义词典,尤其是三维向量,或者您需要的任何内容。

其他提示

如果它“违反了Equals合同”,那么我不确定您是否应该将其用作密钥。

有些东西正在使用它作为键,你真的需要正确的哈希...很不清楚 Equals 逻辑是什么,但两个被认为相等的值必须具有相同的哈希码。不需要具有相同哈希码的两个值相等。

使用常量字符串实际上并没有多大帮助 - 你可以在类型上均匀地分配值,但这就是它...

我很好奇是重写 GetHashCode()并返回一个常量值的原因。为什么违反哈希的想法而不是违反“合同”?而不是重写 GetHashCode()函数并保留 Object 的默认实现?

修改

如果您所做的是这样,那么您可以根据内容而不是引用来使对象匹配,那么您建议使用不同的类只需使用不同的常量即可,但效率非常低。你想要做的是提出一个散列算法,它可以获取你的类的内容,并产生一个平衡速度与均匀分布的值(即散列101)。

我想我不确定你在寻找什么...没有“好”的为这种范式选择常数的方案。一个并不比另一个好。尝试改进对象,以便创建真正的哈希。

当发生哈希冲突时,HashTable / Dictionary调用Equals来查找您正在寻找的密钥。使用常量哈希码首先消除了使用哈希的速度优势 - 它变成了线性搜索。

你说根据合同没有实施Equals方法。你到底是什么意思?根据违规的类型,HashTable或词典只会很慢(线性搜索)或根本不起作用。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top