为什么赢了';t哈希表返回“true”;ContainsKey“;对于C#中byte[]类型的键?

为什么赢了';t哈希表返回“true”;ContainsKey“;对于C#中byte[]类型的键?,c#,hashtable,assertions,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)); 为什么这个断言失败了?作为基元类型的数组不应该使用对象引用,是吗?那么为什么它会返回false呢?我能做些什么

考虑以下代码:

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));
为什么这个断言失败了?作为基元类型的数组不应该使用对象引用,是吗?那么为什么它会返回false呢?我能做些什么来让这个哈希表工作吗

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

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

一切都正常运转


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

它返回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方法计算哈希来存储对象,任何以后的“命中”都是使用此方法计算的。可以通过基于对象的每个属性(在本例中是数组中的每个字节)返回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;
}

下面是一个示例实现:

  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;
      }
    }
  }
类程序{
静态void Main(字符串[]参数){
字节[]字节=新字节[]{1,2,5,0,6};
字节[]另一个=新字节[]{1,2,5,0,6};
Hashtable ht=新的Hashtable(new ByteArrayComparer());
ht.Add(字节,“hi”);
System.Diagnostics.Debug.Assert(ht.ContainsKey(另一个));
}
私有类ByteArrayComparer:IEqualityComparer{
public int GetHashCode(对象obj){
字节[]arr=obj作为字节[];
int hash=0;
foreach(arr中的字节b)hash^=b;
返回散列;
}
公共新布尔等于(对象x、对象y){
字节[]arr1=x作为字节[];
字节[]arr2=y作为字节[];
如果(arr1.Length!=arr2.Length)返回false;
对于(int-ix=0;ix

如果在哈希表中放入数千个数组,则应该使用更强的哈希。查看一个例子。

所以我唯一的“实数”选项是将字节数组转换为真基元,例如整数或字符串,然后使用它?找到绝对最有效的方法来定位此表中的特定字节[]对于我正在进行的电子项目来说是最紧迫的。你有什么建议吗?有没有一种数组类型可以用作值类型?可能是
System.Collections中的某个东西我没听说过?您是否错过了他建议您实现一个比较器以传递到哈希表的部分?:-)更具体地说,您希望实现
IEqualityComparer
接口(定义适当的
Equals(object,object)
GetHashCode(object)
方法),并在创建哈希表时将其传入。但这不意味着我必须创建自己的对象来存储字节数组吗?这不是比使用普通的旧字节[]效率低很多吗?System.Array是支持类,在MSDN上被视为引用类型,假设我们将这两个数组散列为相同的值。现在假设在上面的代码之后添加了“bytes[0]=100;”。现在ht.Contains(字节)会返回true还是false?记住,查找是在哈希值上完成的。这就是为什么对引用而不是内容进行散列:内容可以更改。这正是我想看到的,但是在
Equals(object x,object y)
方法中,字节数组的base64转换不是比循环遍历数组中的每个项更有效吗(特别是当数组大小为几十KB时)?否,Convert.ToBase64String在数组中的每个项目内部循环以生成字符串。然后需要另一个循环来比较字符串。这是您看不到的代码,但速度会慢一些。好的,根据我的单个查找测试,上述实现在0.4ms内执行,同时执行`if(Convert.ToBase64String(arr1)`!=Convert.ToBase64String(arr2))return false;`在0.3ms内执行。不尝试nick pick,但正如我之前所说的(尽管这看起来很疯狂),对于这个应用来说,几乎每一部分毫秒都很重要。我计算过,在这个应用的生命周期中,1ms的节省将使应用程序的执行时间缩短几十个小时。但是,非常感谢这一点,这是一个很好的帮助(除非你认为Base64真的会因为某种原因而变得不好)。这没有任何意义,但请使用您知道最有效的方法。GetHashCode()对于速度来说是最重要的一个,使用真实数据进行测试。@Ash对于性能密集型应用程序,
GetHashCode
实现可能太慢,因为它在整个数组中循环。您需要
GetHashCode
来加快速度,但冲突很少-您必须调整它。您是否有一个期望t的字节子集o对于大多数阵列是否有所不同?