如何为这种情况实现GetHashCode?

时间:2014-08-27 09:58:49

标签: c# gethashcode

我正在尝试实现一个IEqualityComparer<string>,它基本上比较两个字符串,(假设我们有两个字符串xyxyy开始,x它们应被视为相等。

public bool Equals(string x, string y)
{
    return x.StartsWith(y) || y.StartsWith(x);
}

public int GetHashCode(string obj)
{
    return obj.GetHashCode();
}

实现Equals方法的过程非常简单。但是GetHashCode不是,我想不出任何正确实现它的方法。我编写了一个这样的测试程序:

string[] values = {"hell", "hello", "foo", "fooooo"};

var result = values.Distinct(new StringComparer());

foreach(var x in result)
   Console.WriteLine(x);

由于GetHashCode

,我得错了结果
hell
hello
foo
fooooo

显然,我可以通过从Equals为所有值返回相同的值来强制调用GetHashCode方法,但我想知道是否有另一种方法来实现它,因为性能很关键。有没有办法正确地为我的情况实施GetHashCode方法?

注意:我知道它很模糊,但如果您有更好的想法可以自由编辑,我找不到更好的标题。


编辑:我将在网址上使用此逻辑。在我的情况下,前20个字符是相等的。例如:

http://www.foo.com/bar?id=3
http://www.foo.com/bar?id=3&fooId=23

2 个答案:

答案 0 :(得分:4)

问题在于你对平等的定义:平等必须是可传递的。但它不是你的情况。采用以下三个值:

* f
* freeze
* foo

然后f == freezefoo == f,但freeze != foo

另请参阅Implementing the Equals Method上的MSDN,其中包含:

  当且仅当(x.Equals(y) && y.Equals(z))返回true时,

x.Equals(z)才返回true。

正确的相等定义会产生被认为相等的不同值集。如果你有这些,你可以为每个集定义一个“规范”表示,并计算规范值的哈希值,这样每个集合都有其哈希码。但这仅适用于具有传递性的操作(以及可交换和反身,这两个属性都包含在您的定义中)。

由于您的相等定义不可传递,因此您无法定义此类集,因此您也无法找到正确的哈希码。

但它也提出了其他问题。举个例子:

string[] values = { "hell", "hello", "foo", "fooooo" };
var result = values.Distinct(new StringComparer());

您希望将哪些值放入result?你总是想要最短的版本吗?您的代码无法保证这一点,结果将取决于Distinct的内部实现。

实施EqualityComparer可能是您实际问题的次优方法。你想要实现什么目标?

答案 1 :(得分:2)

由于字符串彼此相等,具体取决于您与之比较的字符串,因此任何字符串都可以等于另一个字符串。因此,只有一种方法可以实现GetHashCode方法;为所有字符串返回相同的值:

public int GetHashCode(string obj) {
  return 0;
}

这自然会给人一种可怕的分配。字典将具有O(n)查找时间而不是O(1),但它起作用,并且它是使其适用于这种相等比较的唯一方法。