During implementation, often question rises on how to sort a collection of objects. To sort a collection requires how objects can first of all be compared to each other. A value type such as int, double, float can be compared if both of the objects have equal values. However, a reference type such as a class with multiple fields, the question is often difficult to answer. Well, in other words it depends. It depends how two objects are said to be compared / equated; when all fields have the same value or one of them is enough to decide if they are equal.
C# provides a variety of interfaces to achieve the required behavior. Let’s have a look on them one by one:
public class Car
{
public string Name { get; set; }
public int MaxSpeed { get; set; }
}
IComparable Interface
Interface has a CompareTo method that takes a reference type as a parameter and returns an integer based on if current instance precedes, follows or occurs in the same position in the sort order as the other object (MSDN).
The implementation of the CompareTo(Object) method must return an Int32 that has one of the three values, as in the following table.
Value |
Meaning |
Less than zero |
The current instance precedes the object specified by the CompareTo method in the sort order. |
Zero |
This current instance occurs in the same position in the sort order as the object specified by the CompareTo method. |
Greater than zero |
This current instance follows the object specified by the CompareTo method in the sort order. |
Example
public class Car: IComparable
{
public string Name
{
get;
set;
}
public int MaxSpeed
{
get;
set;
}
public int CompareTo(object obj)
{
if (!(obj is Car))
{
throw new ArgumentException("Compared Object is not of car");
}
Car car = obj as Car;
return Name.CompareTo(car.Name);
}
}
At client
private static void Main(string[] args)
{
Car[] cars = new Car[]
{
new Car()
{
Name = "Zinco"
}, new Car()
{
Name = "VW"
}, new Car()
{
Name = "BMW"
}
};
Array.Sort(cars);
Array.ForEach(cars, x => Console.WriteLine(x.Name));
}
Output
IComparer interface
The CompareTo method from IComparable interface can sort on only one field at a time, so sorting on different properties with it is not possible. IComparer interface provides Compare method that Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other.
A class that implements the IComparer interface must provide a Compare method that compares two objects.
For example, you could create a CarComparer class that implements IComparer and that has a Compare method that com¬pares Car objects by Name. You could then pass a CarComparer object to the Array.Sort method, and it can use that object to sort an array of Car objects.
public class CarComparer: IComparer < Car >
{
public enum SortBy
{
Name,
MaxSpeed
}
private SortBy compareField = SortBy.Name;
public int Compare(Car x, Car y)
{
switch (compareField)
{
case SortBy.Name:
return x.Name.CompareTo(y.Name);
break;
case SortBy.MaxSpeed:
return x.MaxSpeed.CompareTo(y.MaxSpeed);
break;
default:
break;
}
return x.Name.CompareTo(y.Name);
}
}
At client side
private static void Main(string[] args)
{
Car[] cars = new Car[]
{
new Car()
{
Name = "Zinco"
}, new Car()
{
Name = "VW"
}, new Car()
{
Name = "BMW"
}
};
var carComparer = new CarComparer();
carComparer.compareField = CarComparer.SortBy.MaxSpeed;
Array.Sort(cars, carComparer);
}
Output
IEquatable Interface
If a class implements the IComparable interface, it provides a CompareTo method that enables you to determine how two objects should be ordered. Sometimes, you may not need to know how two objects should be ordered, but you need to know instead whether the objects are equal. The IEquatable interface provides that capability by requiring a class to provide an Equals method.
class Employee: IEquatable < Person >
{
public string FirstName
{
get;
set;
}
public string LastName
{
get;
set;
}
public bool Equals(Employee other)
{
return ((FirstName == other.FirstName) && (LastName == other.LastName));
}
}
At client
// The List of Persons.
private List < Employee > Employees = new List < Employee > ();
// Add a Person to the List.
// Make the new Person.
Employee emp = new Employee()
{
FirstName = “James”
LastName = “Moore”
};
if (Employees.Contains(emp))
{
MessageBox.Show("The list already contains this employee.");
}