The object that invokes Compare method does not belong to the types of objects which are being compared. The invoking object belongs to a separate type. In short, The comparer object is separate from the compared objects.
The following NameComparer class implements IComparer non-generic interface. Note. Modern C# developers use IComparer<T> generic interface.
Inside Main method we use:
OUTPUT
Generic version is type-safe.
Next, comes the question of two objects which are being compared. These two objects may or may not belong to same class. For example, we can compare names of Employee and Doctor classes. Here both Employee and Doctor are separate classes. Or, we can compare names of employees which belong to same Employee class.
Now, we consider about IComparable. It exposes a method with signature: int CompareTo(object? obj); Here, IComparable compares two objects of same class/type. The class that implements IComparable may be called Comparable class. So, Comparable class compares two objects of same class in the CompareTo method.
IComparable compares the current instance with another object of the same type and returns an integer that indicates whether the current instance precedes, follows, or occurs in the same position in the sort order as the other object.
| Interface | Who owns comparison logic? | Compares |
| IComparable | Inside the object | this vs another object |
| IComparer | Separate comparer class | any two supplied objects |
Both IComparer and IComparable are used in Array.Sort method to sort objects based on some property of the objects.
Example of same class objects comparison
The followiing example compares ages of two employees and array of employees can be used inside Array.Sort method to sort employees by age.
// Employee has Bonus
class Bonus
{
public Bonus(int amount)
{
Amount = amount;
}
public int Amount { get; set; }
}
internal class Employee
{
private int _Age;
// initialize data using CTOR
public Employee(int id, string name, int age, int bonus)
{
Id = id;
Name = name;
Age = age;
Bonus = new Bonus(bonus); // reference type
}
// to get data, we need properties
public Bonus Bonus { get; set; }
public int Id { get; } // read-only, Id cannot be updated
public string? Name { get; set; } // read-write, name can be updated
public int Age // read-write, age can be updated
{
get { return _Age; }
set
{
if (value < 18)
{
throw new ArgumentException("Age must be above 18");
}
else
{
_Age = value;
}
}
}
}using System.Collections;
class NameComparer : IComparer
{
public int Compare(object? x, object? y)
{
//step1, compare datatypes
if (x is Employee e1 && y is Employee e2)
{
return string.Compare(e1.Name, e2.Name, StringComparison.OrdinalIgnoreCase);
}
else
{
throw new ArgumentException("Employees Data required.");
}
}
}
- array of employees as 1st argument of Array.Sort static method and
- an instance of the class that implements IComparer as 2nd argument.
// array of employees
Employee[] employees = new Employee[5];
employees[0] = new Employee(1001,"Bhim",35,4000);
employees[1] = new Employee(1002,"Ajay",25,3500);
employees[2] = new Employee(1003,"Vijay",43,4200);
employees[3] = new Employee(1004,"Rakesh",27,3200);
employees[4] = new Employee(1005,"Mohan",22,3100);
Console.WriteLine("original array ==>");
foreach (var emp in employees)
{
Console.WriteLine($"Id {emp.Id}, Name {emp.Name}, Age {emp.Age}");
}
Array.Sort(employees, new NameComparer());
Console.WriteLine("\nsorted by Age ==>");
foreach (var emp in employees)
{
Console.WriteLine($"Age {emp.Age}, Id {emp.Id}, Name {emp.Name}");
}original array ==>
Id 1001, Name Bhim, Age 35
Id 1002, Name Ajay, Age 25
Id 1003, Name Vijay, Age 43
Id 1004, Name Rakesh, Age 27
Id 1005, Name Mohan, Age 22
sorted by Age ==>
Age 25, Id 1002, Name Ajay
Age 35, Id 1001, Name Bhim
Age 22, Id 1005, Name Mohan
Age 27, Id 1004, Name Rakesh
Age 43, Id 1003, Name Vijay
Generic version Example
The following code shows how NameComparer class implements IComparer<T> generic interface.
using System.Collections.Generic;
class NameComparer : IComparer<Employee>
{
public int Compare(Employee? x, Employee? y)
{
if (x == null || y == null)
throw new ArgumentException("Employees data required.");
return string.Compare(
x.Name,
y.Name,
StringComparison.OrdinalIgnoreCase);
}
}
No comments:
Post a Comment