Почему Hashtable не возвращает true для «ContainsKey» для ключа типа byte [] в C #? - PullRequest
2 голосов
/ 15 декабря 2009

Рассмотрим следующий код:

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? Могу ли я что-нибудь сделать, чтобы эта хэш-таблица работала?

Ответы [ 4 ]

7 голосов
/ 15 декабря 2009

Будучи массивом примитивного типа, не следует использовать ссылку на объект, не так ли?

Да, должно. Массивы являются ссылочными типами.

Все работает как положено.

Если вам нужно другое поведение, вы можете реализовать компаратор для массивов, который сравнивает содержимое и передает его в хеш-таблицу.

4 голосов
/ 15 декабря 2009

Вот пример реализации:

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

Вам следует использовать более сильный хеш, если вы положили тысячи массивов в хеш-таблицу. Проверьте этот пост для примера.

0 голосов
/ 15 декабря 2009

По умолчанию ссылочные типы сравниваются по их ссылкам, если только метод 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;
}
0 голосов
/ 15 декабря 2009

Возвращает 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());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...