对于C#中byte []类型的键,为什么Hashtable不会为“ContainsKey”返回true?

时间:2009-12-15 03:46:14

标签: c# hashtable assertions

请考虑以下代码:

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 个答案:

答案 0 :(得分:7)

  

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

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

一切都按照预期的方式运作。

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

答案 1 :(得分: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;
      }
    }
  }

如果在哈希表中放置数千个数组,则应该使用更强的哈希。请查看this post以获取示例。

答案 2 :(得分: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());

答案 3 :(得分:0)

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

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

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