2

考虑以下代码:

byte[] bytes = new byte[] { 1, 2, 5, 0, 6 };
byte[] another = new byte[] { 1, 2, 5, 0, 6 };

Hashtable ht = new Hashtable();
ht.Add(bytes, "hi");
Assert.IsTrue(ht.ContainsKey(another));

为什么这个断言会失败?作为原始类型的数组不应该使用对象引用,不是吗?那么为什么它会返回假呢?我能做些什么来使这个哈希表工作吗?

4

4 回答 4

7

作为原始类型的数组不应该使用对象引用,不是吗?

是的,它应该。数组是引用类型。

一切都按预期工作。

如果你想要不同的行为,你可以为数组实现一个比较器来比较内容并将其传递给哈希表。

于 2009-12-15T03:48:44.750 回答
4

这是一个示例实现:

  class Program {
    static void Main(string[] args) {
      byte[] bytes = new byte[] { 1, 2, 5, 0, 6 };
      byte[] another = new byte[] { 1, 2, 5, 0, 6 };

      Hashtable ht = new Hashtable(new ByteArrayComparer());
      ht.Add(bytes, "hi");
      System.Diagnostics.Debug.Assert(ht.ContainsKey(another));
    }

    private class ByteArrayComparer : IEqualityComparer {
      public int GetHashCode(object obj) {
        byte[] arr = obj as byte[];
        int hash = 0;
        foreach (byte b in arr) hash ^= b;
        return hash;
      }
      public new bool Equals(object x, object y) {
        byte[] arr1 = x as byte[];
        byte[] arr2 = y as byte[];
        if (arr1.Length != arr2.Length) return false;
        for (int ix = 0; ix < arr1.Length; ++ix)
          if (arr1[ix] != arr2[ix]) return false;
        return true;
      }
    }
  }

如果将数千个数组放入哈希表中,则应使用更强的哈希。查看此帖子以获取示例。

于 2009-12-15T04:27:03.813 回答
0

它返回 false 因为哈希不匹配。如果 GetHashCode() 没有为相同的值生成可重复的散列,它将无法在字典中工作。

byte[] bytes = new byte[] { 1, 2, 5, 0, 6 };
byte[] another = new byte[] { 1, 2, 5, 0, 6 };

string astring = "A string...";
string bstring = "A string...";

MessageBox.Show(bytes.GetHashCode() + " " + another.GetHashCode() + " | " + astring.GetHashCode() + " " + bstring.GetHashCode());
于 2009-12-15T03:53:28.147 回答
0

默认情况下,引用类型通过它们的引用进行比较,除非该类型的 Equals 方法已被覆盖。

因为您想将引用类型用作 has 表中的键,您还应该重写 GetHashCode 方法,以便“相等”的对象产生相同的哈希码。

散列表通过使用 GetHashCode 方法计算散列来存储对象,并且使用此方法计算任何以后的“命中”。您可以通过将 GetHashCode 返回的值基于对象的每个属性(在您的情况下为数组中的每个字节)来执行此操作。这是我使用它的一个示例,您也可以在 IEqualityComparer 中执行此操作,您可以在哈希表中使用它:

 public override int GetHashCode() {
        int hash = 17;
  hash = hash * 23 + DrillDownLevel.GetHashCode();
  hash = hash * 23 + Year.GetHashCode();

  if (Month.HasValue) {
    hash = hash * 23 + Month.Value.GetHashCode();
  }

  if (Week.HasValue) {
    hash = hash * 23 + .Week.Value.GetHashCode();
  }

  if (Day.HasValue) {
    hash = hash * 23 + obj.Day.Value.GetHashCode();
  }

  return hash;
}
于 2009-12-15T04:01:55.867 回答