#c_sharp #net
Троелсен в своей книге, советует переопределить метод ToString() у класса(переопределенная версия возвращает строку из полей всего класса через пробел), а потом в методе GetHashCode вызывать this.ToString().GetHashCode(). Где-то читал критику такой реализации, например, вызов ToString() будет порождать мусор. Правда ли, что она не очень хороша. Какие могут быть альтернативы?
Ответы
Ответ 1
Проблема со строкой состоит в том, что GetHashCode() может вызываться очень часто, много тысяч раз в секунду. Например, при поиске элемента в HashSetили поиске ключа в Dictionary у каждого искомого элемента берётся хэшкод. Если при этом будет каждый раз создаваться временная, никому за пределами метода не нужная строка, их потом должен будет очистить сборщик мусора. Поэтому функция GetHashCode должна быть по возможности быстрой и не создавать дополнительных объектов. По поводу того, как же лучше считать хэшкод, я бы посоветовал немного переделанный код из ответа @Umed: public override int GetHashCode() { unchecked { int hash = 17; hash = hash * 23 + field1.GetHashCode(); // для поля типа-значения, например int hash = hash * 23 + field2.GetHashCode(); // то же самое if (field3 != null) // а это для поля ссылочного типа hash = hash * 23 + field3.GetHashCode(); return hash; } } Вместо 17 и 23 можно взять другие разные простые числа. Ещё по теме: Почему при переопределении Equals советуют также переопределять GetHashCode. Ответ 2
Как вариант, можно посчитать его как сумму хэшей его полей: public override int GetHashCode() { int result; uncheked { // если поле ссылочного типа, // то необходима проверка на null // если field1 будет null, то подставится 0 result = this.field1?.GetHashCode() ?? 0; result += this.field2?.GetHashCode() ?? 0; //... result += this.fieldN.GetHashCode(); } return result; } Либо через создание анонимного класса (подсмотрел в английской SO): public override int GetHashCode() { return new { this.field1, this.field2, /*... ,*/ this.fieldN }.GetHashCode(); } Такой вариант тоже работает достаточно быстро, но за тем исключением, что каждый вызов порождает анонимный класс. Там же можно посмотреть ответ Джона Скита. Он накидал алгоритм с выбором двух случайных констант (они не меняются, случайных - потому что Вам надо их придумать один раз) и подсчёта хэша следующим образом: public override int GetHashCode() { unchecked { int hash = 17; // если поле ссылочного типа, // то необходима проверка на null hash = hash * 23 + field1?.GetHashCode() ?? 0; // если это, например, int, то проверка ни к чему hash = hash * 23 + field3.GetHashCode(); return hash; } } Добавил от себя проверку на null, о которой он там пишет в ответе Советую перейти по ссылке и посмотреть, там много полезного написано.
Комментариев нет:
Отправить комментарий