开发者

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

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.A开发者_运维问答dd(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?


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.


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.


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


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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜