Why won't a Hashtable return true for “ContainsKey” for a key of type byte[] in C#?

家住魔仙堡 提交于 2019-12-31 03:15:07

问题


Consider the following code:

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

Why does this assertion fail? Being an array of a primitive type shouldn't use using the object reference, should it? So why would it return false? Is there anything I can do to make this hashtable work?


回答1:


Here's a sample implementation:

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

You should use a stronger hash if you put thousands of arrays in the hash table. Check this post for an example.




回答2:


Being an array of a primitive type shouldn't use using the object reference, should it?

Yes it should. Arrays are reference types.

Everything is working as it's supposed to.

If you want different behaviour, you can implement a comparator for arrays that compares the contents and pass that to the hashtable.




回答3:


It returns false because the hashes don't match. If GetHashCode() doesn't produce a repeatable hash for the same value it won't work in a dictionary.

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



回答4:


By default reference types are compared by their references, unless the Equals method for that type has been overidden.

Because you want to use the reference type as a key in a has table you should also override the GetHashCode method, so that objects that are 'equal' produce the same hash code.

A hash table stores objects by computing the hash using the GetHashCode method, and any later 'hits' are calculated using this. You can do this by basing the value returned by GetHasshCode on each of the properties of the object, in your case each of the bytes in the array. This is an example of where I used it you can also do this in an IEqualityComparer which you could use in your hashtable:

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


来源:https://stackoverflow.com/questions/1905038/why-wont-a-hashtable-return-true-for-containskey-for-a-key-of-type-byte-in

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!