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

请考虑以下代码:

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)); 

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

这是一个示例实现:

  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; } } } 

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

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

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

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

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

它返回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()); 

默认情况下,引用类型按引用进行比较,除非该类型的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; }