我之前已经知道这个问题的变化,但我还没有发现任何具体针对我所问的问题。
在.NET中,我们有IEqualityComparer<T>
,其中包含以下内容:
public interface IEqualityComparer<T>
{
public bool Equals(T x, T y);
public int GetHashCode(T obj);
}
所以,我的问题是为什么不将它分成两个接口,分别是:
public interface IEqualityComparer<T>
{
public bool Equals(T x, T y);
}
public interface IHashProvider<T> : IEqualityComparer<T>
{
public int GetHashCode(T obj);
}
换句话说,我可以看到为什么在对象上执行GetHashCode
的任何情况下,你几乎肯定也需要知道如何执行Equals
。此外,Equals
的定义是正确实现GetHashCode
的要求之一(如果两个对象相等,它们的哈希码也必须相等)。
然而,反过来看,这似乎并非如此。想象一下Equals
的某些自定义实现检查两个对象是否相等,但是没有执行涉及哈希码的任何操作的情况并不难想象。
是否有任何理由将界面拆分为与上述类似,允许方法需要IHashProvider<T>
(或任何它将被称为)或IEqualityComparer<T>
取决于它们是否会或者不会使用哈希码?这只是一个历史性的决定,现在改变太麻烦了吗?或者是否有一些原因让我忽略了总是在GetHashCode
旁边实施Equals
这一点非常重要?
答案 0 :(得分:3)
将IEqualityComparer<T>
添加到.NET框架的原因是,如果您无法使用不同的Equals
覆盖修改类,则允许您自定义基于哈希的容器的逻辑/ GetHashCode
(例如,它在其他人的库中)或者您不希望因任何其他原因更改默认实现 - 例如,为了向后兼容。这是拥有此接口的主要目的:您将其提供给哈希容器,并使用它而不是对象附带的Equals
/ GetHashCode
逻辑。
平台设计人员似乎没有自定义哈希容器之外的IEqualityComparer<T>
接口的用例。当外部提供的Equals
本身没有GetHashCode
时,很难想出一个场景。 .NET平台已经为需要通过Predicate<T1,T2>
外部化双变量(或N变量)检查的用户提供了一种简洁的机制,所以如果你想编写从外部获取相等检查器的代码,你可以这样做:
void MyFunction(IEnumerable<T> one, IEnumerable<T> two, Predicate<T,T> equalityCheker) {
foreach (var a in one) {
foreach (var b in two) {
if (equalityCheker(a, b)) {
Console.WriteLine("Equal: {0} {1}", a, b);
}
}
}
}
答案 1 :(得分:2)
原因是添加两个单独的接口而不是一个接口是不值得的。我强烈建议您阅读Eric Gunnerson撰写的名为“Minus 100 points”的文章,其中他讨论了向C#添加功能的成本。归结为将GetHashCode()
与Equals()
分开并没有得到足够的证据来保证它是独立的界面。
我还建议阅读一些类似主题的文章
答案 2 :(得分:0)
如果你想比较两个不可变的对象是否相等,那么 可能 要更快,首先检查它们是否具有相同的哈希值码。 - 由于对象是不可变的,因此它们的哈希码是常量,因此它也可以保存为对象状态的一部分,以便在字典中更快地使用。
当您在字典中搜索对象时,搜索是通过密钥的哈希码完成的,以找到正确的bin,然后使用Equals()来查找正确的密钥。
换句话说,如果要查找或比较对象,通常首先要比较它们的哈希码是很重要的,因此相等接口也应该能够获取哈希码。