Главная » C# » Реализация метода GetHashCodeQ в Visual C# (Sharp)

0

В документации MSDN метод object. GetHashCode о описывается следующим обром (http://msdn2.microsoft.cora/en-us/library/system.object.gethashcode(vs.71).aspx): "Данный метод можно подменять в производном классе. Значимые классы должны подменять этот метод, чтобы предоставить функцию хеширования, соответствуую классу и обеспечивающую лучшее распределение хэш-таблицы. Классы, корые могут быть  использованы эш-таблице в качестве ключа, также должны подменять этот метод, т. к. объекты, используемые в качестве ключа хэш-таблицы, должны генерировать свой хэш-код посредством данного метода. Но если объекты, используемые в качестве ключа, не предоставляют пригодной реализации метода GetHashCode, можно предоставить другого поставщика хэш-кода, основанного на интерфейс е  System.Collections. IHashCodeProvider, пр и  создани и  Hashtable".

Но что это по существу означает? Целью (в большинстве случаев) метода GetHashCode () является однозначно идентифицировать тип в коллекции других типов с помощью уникального хэш-кода. Скажем, что нам нужно создать таблицу объектов одного типа. Такая ситуация может возникнуть при создании коллекции и сохранении в ней множественных объектов. Обычно эти объекты можно разделить с помощью метода GetHashCode (). Обычно потому, что метод GetHashCode () рабает лишь приблизительно. Чтобы удостовериться в том, что один объект равняется другому, необходимо реализовать метод Equals ().

Реализацию же хэш-кода лучше делегировать вспомогательному классу, выпояющему  вся  тяжелую  работу.  Надежный  метод  создания  такого  класса  описан в книге Джошуа Блоха "Java. Эффективное программирование’". Суть его состоит

2  Блох Дж. Java. Эффективное программирование. — М.: Лори, 2002.

в следующем. В переменной сохраняется какая-либо  ненулевая  константа,  скем 17. Потом для каждого члена данных типа выполняется математическая опация. Ее результатом являются целочисленные значения, которые последователо умножаются и складываются. Выполняемая операция является специфичной для типа и определяется следующим образом:

• bool — если истина, то возвращается 0; в противном случае возвращается 1;

• byte, char, short или int — возвращается значение типа;

• long — возвращаетс я   (int)(fMf >>> 32));

• float  —    возвращается    результат    выполнения    над    значением     метода

Convert.ToInt32;

• object   —        возвращается        значение,        сгенерированное         методом

obj ect.GetHashCode();

• array — выполняется индивидуальная обработка каждого элемента в цикле.   Эти  правила  реализованы  в  классе HashCodeAutomater. Далее  приводится  сокра-

щенный вариант реализации класса:

public class HashCodeAutomater; private readonly int _constant; private int _runningTotal;

public HashCodeAutomater() {

_constant = 37;

„.runningTotal = 17;

}

public HashCodeAutomater AppendSuper(int superHashCode) {

_runningTotal = _runningTotal * _runningTotal + superHashCode; return this;

}

public HashCodeAutomater Append(Object obj) { if (obj == null) {

_runningTotal = _runningTotal * _constant;

} else {

if (obj.GetTypeO.isArray == false) {

_runningTotal = _runningTotal * _runningTotal + obj.GetHashCode();

} else {

if (obj is long[]) {

Append((long[]) obj );

}

// Прочие тесты были удалены для ясности

else {

//Н е массив примитивов Append((Object[]) obj);

}

}

}

return this;

}

public HashCodeAutomater Append(long value) {

_runningTotal = _runningTotal * „constant +

((int) (value A (value » 32)));

return this;

}

public HashCodeAutomater Append(long[] array) { if (array == null) {

_runningTotal = _runningTotal * _constant;

}

else {

for (int i = 0; i < array.Length; i++) { Append(array[i]);

}

}

return this;

}

public HashCodeAutomater Append(Object[] array) { if (array == null) {

_runningTotal = _runningTotal * _constant;

}

else {

for (int i = 0; i < array.Length; i++) { Append(array[i]);

}

}

return this;

}

public int toHashCode() { return _runningTotal;

}

}

Разные реализации метода Append О относятся к одному группированию для одного типа данных — long. Например, имеются варианты метода Append О, принимающие в качестве параметра значение long и массив значений long. Полная реализация класса HashCodeAutomater также имела бы варианты метода Append () для значения short и массива значений short, а также для всех других типов данных. Для строкых типов группировки реализаций метода не имеется, т. к. этот тип рассматривается как объект, имеющий собственную реализацию вычисления хэш-кода.

Обратите внимание в реализациях вариантов метода Append () на то, что результат вычисления складывается с членом данных _runningTotai. Возвращаемым значием является переменная this , чтобы методы можно было соединить последовельно друг С другом. Это позволяет клиенту использовать класс HashCodeAutomater, как показано в следующей реализации метода GetHashCode ():

class HashcodeExample { public int value; public string buffer;

public HashcodeExample(int val, string buf) { value = val;

buffer = buf;

}

public override int GetHashCode() { return new HashCodeAutomater()

.Append(value)

.Append(buffer).toHashCode();

}

}

Реализация класса HashcodeExample имеет два члена данных: value и buffer. Эти два члена данных составляют состояние класса. При  вычислении  значения  хэода экземпляра класса используются не все члены данных. Например, если класс HashcodeExample имеет член данных, который обращается к соединению с базой данных, то этот член данных нельзя использовать при вычислении хэш-кода, т. к. тип соединения с базой данных применяется для получения состояния и не влияет на него — это всего лишь способ достижения цели.

Источник: Гросс  К. С# 2008:  Пер. с англ. — СПб.:  БХВ-Петербург, 2009. — 576 е.:  ил. — (Самоучитель)

По теме:

  • Комментарии