Equals and GetHashCode in C

Equals and GetHashCode

Each implementation of Equals must follow the following conventions:

  • Reflexive: x.equals (x) must return true
  • Symmetry: when x.equals (y) is true, y.equals(x) is also true
  • Transitivity: for any non null application values x,y and Z, if x.equals(y) returns true, and y.equals(z) also returns true, then x.equals(z) must return true
  • Consistency: if an object is compared with another object multiple times, the result is always the same. As long as the application objects of X and y are not modified, x.equals(y) calls x.equals(y) continuously to return the same value l
  • Non null: if x is not null and Y is null, x.equals(y) must be false

GetHashCode:

  • If two equal objects are equal when compared according to the equals method, the hashcode method of any one of the two objects must produce the same integer.
  • When we do not modify the object, we call hashcode multiple times to return the same integer. If we execute it multiple times in the same application program, the integer returned each time can be inconsistent
  • If two objects are not equal according to the equals method, the hashcode method of any one of the two objects is called, which is not the same integer. But different objects and different integers may improve the performance of hash table

IEqualityComparer implementation

Next, we create a student class to further realize the comparison of our object data

    public class Student
    {
        public string Name { get; set; }

        public int Age { get; set; }
    }

Through the following code, we will implement our filtering through the distinct method

    class Program
    {
        static void Main(string[] args)
        {
            List<Student> students = new List<Student>
            {
                new Student{ Name = "MR.A", Age = 32},
                new Student{ Name = "MR.B", Age = 34},
                new Student{ Name = "MR.A", Age = 32}  
            };
            Console.WriteLine("distinctStudents has Count = {0}", students.Distinct().Count());//distinctStudents has Count = 3
            Console.ReadLine();
        }
    }

What we need to achieve is to ignore the objects with the same data, but it doesn't achieve our expected effect. Because the default comparison of distinct is the reference of objects... So it can't achieve our expected effect. Let's modify it to achieve our expected effect

By default, Equals has the following behavior:

  • If the instance is a reference type, Equals returns true only if the references are the same.
  • If the instance is a value type, Equals returns true only if the type and value are the same.

Distinct(IEnumerable, IEqualityComparer)

Returns a non - repeating element in a sequence by comparing values using the specified IEqualityComparer

Type parameter

  • Element type of TSource source.

    parameter

  • source IEnumerable the sequence from which to remove duplicate elements.
  • comparer IEqualityComparer the IEqualityComparer used to compare values.

Return

  • IEnumerable
    An IEnumerable that contains non repeating elements in the source sequence.

Let's look at the following code snippet

    public class StudentComparator : EqualityComparer<Student>
    {
        public override bool Equals(Student x,Student y)
        {
            return x.Name == y.Name && x.Age == y.Age;
        }

        public override int GetHashCode(Student obj)
        {
            return obj.Name.GetHashCode() * obj.Age;
        }
    }

If two Equals return true and GetHashCode return the same hash code, the two objects are considered equal

Override Equals and GetHashCode

var stu1 = new Student { Name = "MR.A", Age = 32 };
var stu2 = new Student { Name = "MR.A", Age = 32 };
   
bool result = stu1.Equals(stu2); //false because it's reference Equals

The result of the above code fragment is unexpected. We will further implement the code to achieve the expected effect

    public class Student
    {
        public string Name { get; set; }

        public int Age { get; set; }

        public override bool Equals(object obj)
        {
            var stu = obj as Student;
            if (stu == null) return false;
            return Name == stu.Name && Age == stu.Age; 
        }
        public override int GetHashCode()
        {
            return Name.GetHashCode() * Age;
        }
    }
    
  var stu1 = new Student { Name = "MR.A", Age = 32 };
  var stu2 = new Student { Name = "MR.A", Age = 32 };

  bool result = stu1.Equals(stu2); //result is true

We will use LINQ Distinct method to filter and query, and check Equals and GetHashCode at the same time

    List<Student> students = new List<Student>
    {
        new Student{ Name = "MR.A", Age = 32},
        new Student{ Name = "MR.B", Age = 34},
        new Student{ Name = "MR.A", Age = 32}
    };
    Console.WriteLine("distinctStudents has Count = {0}", students.Distinct().Count()); //distinctStudents has Count = 2

Tags: C# Fragment

Posted on Fri, 31 Jan 2020 04:18:19 -0800 by Stelios