Хотя в настоящем примере мы не собираемся помещать объекты Person внутрь System.Collections.Hashtable, ради полноты изложения давайте переопределим метод GetHashCode. Существует много алгоритмов, которые можно применять для создания хеш-кода, как весьма изощренных, так и не очень. В большинстве ситуаций есть возможность генерировать значение хеш-кода, полагаясь на реализацию метода GetHashCode из класса System.String.
Учитывая, что класс String уже имеет эффективный алгоритм хеширования, использующий для вычисления хеш-значения символьные данные объекта String, вы можете просто вызвать метод GetHashCode с той частью полей данных, которая должна быть уникальной во всех экземплярах (вроде номера карточки социального страхования), если ее удается идентифицировать. Таким образом, если в классе Person определено свойство SSN, то вы могли бы написать следующий код:
// Предположим, что имеется свойство SSN.
class Person
{
public string SSN {get; } = "";
public Person(string fName, string lName, int personAge,
string ssn)
{
FirstName = fName;
LastName = lName;
Age = personAge;
SSN = ssn;
}
// Возвратить хеш-код на основе уникальных строковых данных.
public override int GetHashCode => SSN.GetHashCode;
}
В случае использования в качестве основы хеш-кода свойства, допускающего чтение и запись, вы получите предупреждение. После того, как объект создан, хеш-код должен быть неизменяемым. В предыдущем примере свойство SSN имеет только метод get, что делает его допускающим только чтение, и устанавливать его можно только в конструкторе.
Если вы не можете отыскать единый фрагмент уникальных строковых данных, но есть переопределенный метод ToString, который удовлетворяет соглашению о доступе только по чтению, тогда вызывайте GetHashCode на собственном строковом представлении:
// Возвратить хеш-код на основе значения, возвращаемого
// методом ToString для объекта Person.
public override int GetHashCode => ToString.GetHashCode;
Тестирование модифицированного класса Person
Теперь, когда виртуальные члены класса Object переопределены, обновите операторы верхнего уровня, чтобы протестировать внесенные изменения:
Console.WriteLine("***** Fun with System.Object *****\n");
// ПРИМЕЧАНИЕ: мы хотим, чтобы эти объекты были идентичными
// в целях тестирования методов Equals и GetHashCode.
Person p1 = new Person("Homer", "Simpson", 50, "111-11-1111");
Person p2 = new Person("Homer", "Simpson", 50, "111-11-1111");
// Получить строковые версии объектов.
Console.WriteLine("p1.ToString = {0}", p1.ToString);
Console.WriteLine("p2.ToString = {0}", p2.ToString);
// Протестировать переопределенный метод Equals.
Console.WriteLine("p1 = p2?: {0}", p1.Equals(p2));
// Протестировать хеш-коды.
// По-прежнему используется хеш-значение SSN
Console.WriteLine("Same hash codes?: {0}", p1.GetHashCode == p2.GetHashCode);
Console.WriteLine;
// Изменить значение Age объекта p2 и протестировать снова.
p2.Age = 45;
Console.WriteLine("p1.ToString = {0}", p1.ToString);
Console.WriteLine("p2.ToString = {0}", p2.ToString);
Console.WriteLine("p1 = p2?: {0}", p1.Equals(p2));
// По-прежнему используется хеш-значение SSN
Console.WriteLine("Same hash codes?: {0}", p1.GetHashCode == p2.GetHashCode);
Console.ReadLine;
Ниже показан вывод:
***** Fun with System.Object *****