In C#, when dealing with hash-based data structures like hash tables, dictionaries, and sets, we rely on two methods: GetHashCode()
and Equals()
. The GetHashCode()
method creates a unique code for each item in these data structures, while the Equals()
method is used to check if two objects are the same.
Overriding both the GetHashCode()
and Equals()
methods together is essential to ensure consistent behavior. When two objects are considered equal based on the Equals()
method, their hash codes must be identical. Unexpected behavior and performance concerns may occur if the GetHashCode()
method is improperly overridden while storing and retrieving objects from hash-based collections.
GetHashCode()
The Object
class’s default implementation, which generates the hash code using the object’s reference address, will be applied if the GetHashCode()
method is not overridden. In this scenario, two objects with different memory addresses but containing the same data will have different hash codes, leading to inaccurate behavior when used in hash-based collections.
We develop a customized hashing technique by overriding the GetHashCode()
method that considers the pertinent features of the object. As a result, objects with identical data will generate the same hash code, allowing for proper storing and retrieval from hash-based collections.
Let’s say that we have a class Student
that represents a student with a name, roll no. and age:
using System;public class Student{public string Name { get; }public int RollNo { get; }public int Age { get; }public Student(string name, int rollno, int age){Name = name;RollNo = rollno;Age = age;}public override bool Equals(object obj){if (obj == null || GetType() != obj.GetType())return false;Student otherStudent = (Student)obj;return Name == otherStudent.Name && RollNo == otherStudent.RollNo && Age == otherStudent.Age;}public override int GetHashCode(){int hash = 11;hash = hash * 18 + Name.GetHashCode();hash = hash * 18 + RollNo.GetHashCode();hash = hash * 18 + Age.GetHashCode();return hash;}}public class Program{public static void Main(){Student student1 = new Student("John Doe", 1001, 25);Student student2 = new Student("Bob Smith", 1002, 30);Student student3 = new Student("John Doe", 1001, 25);Console.WriteLine($"student1 and student2 are equal: {student1.Equals(student2)}");Console.WriteLine($"student1 and student3 are equal: {student1.Equals(student3)}");Console.WriteLine($"HashCode of student1: {student1.GetHashCode()}");Console.WriteLine($"HashCode of student2: {student2.GetHashCode()}");Console.WriteLine($"HashCode of student3: {student3.GetHashCode()}");}}
Lines 3–14: We define a Student
class with three properties: Name
, RollNo
, and Age
. The class also includes a constructor to initialize these properties.
Lines 16–23: The Equals()
method is overridden in the Student
class. It checks if the passed object is not null and is of the same type as Student
. If not, it returns false
immediately. Otherwise, it casts the object to a Student
type and compares its Name
, RollNo
, and Age
properties with the current instance’s properties. If all three properties match, the objects are considered equal, and true
is returned; otherwise, false
is returned.
Lines 25–32: The GetHashCode()
method is also overridden. It generates a hash code based on the Name
, RollNo
, and Age
properties of the Student
object. A straightforward hashing method combines these values into a single hash code.
Lines 39–41: Three Student
class instances—student1
, student2
, and student3
—are created in the Main()
method. In terms of data, student1
and student3
are identical because they share the same Name
, RollNo
, and Age
characteristics.
Line 43: Student1
and Student2
are compared using the Equals()
method, with the outcome being reported to the console. Since they have different data, it will be false
.
Line 44: Student1
and Student3
are also compared using the Equals()
method, with the results being written to the console. They share the same data; therefore, it will be true
.
Lines 46–48: Each Student
instance receives a call to the GetHashCode()
function, and the hash codes returned are reported to the console. Student1
and Student3
will share the same hash code because their data is identical.
In summary, overriding the GetHashCode()
method alongside the Equals()
method is essential to maintaining consistency when working with hash-based collections and to ensure that objects with the same data are considered equal and produce the same hash code.
Free Resources