3

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

其中一些类实现了相同的接口,并且有使用该接口作为键的 Hashmaps。所以我认为每个类至少应该在GetHashCode().

问题是如何选择这个值。我应该简单地让第一个类返回 1,下一个类返回 2,依此类推吗?或者我应该尝试类似的东西

class SomeClass : SomeInterface {
    public overwrite int GetHashCode() {
        return "SomeClass".GetHashCode();
    }
}

所以哈希分布更均匀?(我必须自己缓存返回的值还是微软的编译器能够对此进行优化?)

更新:不可能为每个对象返回单独的哈希码,因为 Equals 违反了合同。具体来说,我指的是这个问题

4

4 回答 4

2

我很好奇重写GetHashCode()和返回常量值的原因是什么。为什么要违反散列的想法,而不是仅仅违反“合同”而不是根本不覆盖GetHashCode()函数并保留默认实现Object

编辑

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

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

于 2009-05-07T15:27:12.703 回答
2

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

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

使用常量字符串并没有太大帮助 - 您将在类型上平均分配值,但仅此而已......

于 2009-05-07T15:29:00.423 回答
1

当散列冲突发生时,HashTable/Dictionary 调用 Equals 来查找您要查找的键。使用恒定哈希码首先消除了使用哈希的速度优势——它变成了线性搜索。

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

于 2009-05-07T15:32:21.303 回答
1

我在编写向量类时遇到了这个确切的问题。我想比较向量是否相等,但浮点运算会产生舍入误差,所以我想要近似相等。长话短说,除非你的实现是对称的、自反的和传递的,否则重写 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!

另一个例子是一个集合:

//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 接口,在您的类中实现它,并向 Dictionary 添加一个扩展方法 GetApprox,该方法枚举查找近似相等的键,并返回关联的值。您还可以为 3 维向量或任何您需要的东西编写自定义字典。

于 2009-05-07T15:42:25.663 回答