Introduction
Some time ago, I was asked a question related to generic List<T>. How to sort any generic list based on some data member of any user defined class. Let me admit that I have been using C#.NET since the last 3 years but at that moment nothing comes into my mind directly. There is a method named Sort()
- that's what the first thought was. So thereafter I tried it by making a sample application. There are various ways to achieve it but with this small article I am posting my solution which I think is very simple.
Background
First let's understand the problem with one simple example. Let's say we are having a list of employees for some organization. Now to generate a report, there are few requirements to sort that list name-wise or employeeid-wise, etc. So our problem is how to achieve it via generic list so that very limited changes allow us to sort it on any of the attributes.
Using the Code
Let's have a user defined Employee
class.
public class Employee
{
#region Private Members
private Int32 empId;
private String empName;
private DateTime empJoiningDate;
#endregion
#region Properties
public Int32 EmployeeId
{
get { return empId; }
set { empId = value; }
}
public String EmployeeName
{
get { return empName; }
set { empName = value; }
}
public DateTime EmployeeJoiningDate
{
get { return empJoiningDate; }
set { empJoiningDate = value; }
}
#endregion
}
Now whenever we want to use the sorted Employee
list, first of all we will create the List<T>
.
List<Employee> myEmployeeList = new List<Employee>();
The next step would be using the Sort()
method & inside the method writing another easy-to-find method CompareTo()
. But the problem with this approach is that sometimes we have to specify that sorting has to be based on some specific attributes only (i.e. ID or Name of the employees).
public int CompareTo(Employee other)
{
return EmployeeName.CompareTo(other.EmployeeName);
}
The above method can be useful only when we are sure about the attribute for which sorting is to be done. Otherwise it's better to have the parameter to be passed for sorting. To achieve this, we should use IComparable<T>
. (Click here for details.)
public class Employee : IComparable<Employee>
{
[...]
public Int32 CompareTo(Employee other)
{
return EmployeeName.CompareTo(other.EmployeeName);
}
[...]
}
Here we are having fix attribute Name
for sorting. To add flexibility, we can use delegates to avoid the code repetition. We can declare multiple delegates for each attribute upon which sorting is allowed.
public class Employee : IComparable<Employee>
{
[...]
public static Comparison<Employee> AgeComparison =
delegate(Employee p1, Employee p2)
{
return p1.empAge.CompareTo(p2.empAge);
};
public static Comparison<Employee> NameComparison =
delegate(Employee p1, Employee p2)
{
return p1.empName.CompareTo(p2.empName);
};
[...]
}
By declaring static
delegates, we can use them without creating the instance of Employee
class while passing as parameter to Sort()
method.
myEmployeeList.Sort(Employee.NameComparison);
[...].myEmployeeList.Sort(Employee.AgeComparison);
Let's have a look at the full code of Employee
class:
public class Employee : IComparable<Employee>
{
#region Private Members
private Int32 empId;
private String empName;
private UInt32 empAge;
#endregion
#region Properties
public Int32 EmployeeId
{
get { return empId; }
set { empId = value; }
}
public String EmployeeName
{
get { return empName; }
set { empName = value; }
}
public UInt32 EmployeeAge
{
get { return empAge; }
set { empAge = value; }
}
#endregion
#region Constructor
public Employee(Int32 id, String name, UInt32 age)
{
this.empId = id;
this.empName = name;
this.empAge = age;
}
#endregion
#region Static Members
public static Comparison<Employee> AgeComparison = delegate(Employee p1, Employee p2)
{
return p1.empAge.CompareTo(p2.empAge);
};
public static Comparison<Employee> NameComparison = delegate(Employee p1, Employee p2)
{
return p1.empName.CompareTo(p2.empName);
};
public static Comparison<Employee> IDComparison = delegate(Employee p1, Employee p2)
{
return p1.empId.CompareTo(p2.empId);
};
#endregion
#region IComparable<Product> Members
public Int32 CompareTo(Employee other)
{
return EmployeeName.CompareTo(other.EmployeeName);
}
#endregion
#region Overridden Methods
public override string ToString()
{
return string.Format("Id: {0} Name: {1} Age: {2}", empId, empName, empAge);
}
#endregion
}
History
- 12th August, 2009 -- Article submitted