Introduction
Stop writing IComparer
classes to sort your custom collections! This article discusses sorting of a user defined collection object based on any of the properties of the business entity. This sorting technique is generic for all the collection objects. You can sort your collection based on their properties.
Scenario
For example consider the "Student
" and "StudentCollection
" classes:
public class Student
{
string name="";
public string Name
{
get{return name;}
set{name = value;}
}
int id=0;
public int Id
{
get{return id;}
set{id = value;}
}
DateTime dob=DateTime.MinValue;
public DateTime DOB
{
get{return dob;}
set{dob = value;}
}
public Student(string name,int id,DateTime Dob)
{
this.name = name;
this.id = id;
this.dob = Dob;
}
}
public class StudentCollection : CollectionBase
{
public StudentCollection()
{
}
}
Student
collection consists of Student
object collection. Student
entity consists of three properties namely, name
, id
and Dob
. Suppose you want to sort the collection based on the Student's Name or Id or DOB, we need to write the Comparer
class for each user defined collection as follows.
Usual way of sorting objects using IComparer and IComparable interfaces
class StudentComparer : IComparer
{
private int intCompType;
public StudentComparer (int sortOrder)
{
intCompType = sortOrder;
}
public int Compare(object x,object y)
{
switch(intCompType)
{
case (int)enuSortOrder.NameAsc:
return ((Student)x).Name.CompareTo(((Student)y).Name);
case (int)enuSortOrder.NameDesc:
return ((Student)y).Name.CompareTo(((Student)x).Name);
}
}
}
Problem
For StudentCollection
we need a StudentComparer
class and for ProductCollection
we need a ProductComparer
class…and so on…. To avoid these cumbersome coding, I wrote a generic "SortableCollectionBase
" class that can be used to sort any custom collection object without tedious coding.
Solution
How it works?
SortableCollectionBase
class uses "GenericComparer
" class for sorting. "GenericComparer
" class implements IComparer
interface and compares the objects based on the public
property (Sort Column) of the class type dynamically irrespective of the collection.
GenericComparer class
public sealed class GenericComparer:IGenericComparer
{
public enum SortOrder
{
Ascending = 0,
Descending = 1
}
Type objectType;
public Type ObjectType
{
get{return objectType;}set{objectType = value;}
}
string sortcolumn = "";
public string SortColumn
{
get{return sortcolumn;}set{sortcolumn = value;}
}
int sortingOrder = 0;
public int SortingOrder
{
get{return sortingOrder;}set{sortingOrder = value;}
}
public int Compare(object x, object y)
{
PropertyInfo propertyInfo =
ObjectType.GetProperty(sortcolumn);
IComparable obj1 =
(IComparable)propertyInfo.GetValue(x,null) ;
IComparable obj2 =
(IComparable)propertyInfo.GetValue(y,null) ;
if(sortingOrder == 0)
return ( obj1.CompareTo(obj2) );
else
return ( obj2.CompareTo(obj1) );
}
}
SortableCollectionBase class
public abstract class SortableCollectionBase :
CollectionBase,ISortable
{
string sortcolumn="";
public string SortColumn
{
get{return sortcolumn;}
set{sortcolumn = value;}
}
GenericComparer.SortOrder sortingOrder =
GenericComparer.SortOrder.Ascending;
public GenericComparer.SortOrder SortingOrder
{
get{return sortingOrder;}set{sortingOrder = value;}
}
Type sortObjectType;
public Type SortObjectType
{
get{return sortObjectType;} set{sortObjectType = value;}
}
public virtual void Sort()
{
if(sortcolumn == "")
throw new Exception("Sort column required.");
if(SortObjectType == null)
throw new Exception("Sort object type required.");
IGenericComparer sorter = new GenericComparer();
sorter.ObjectType = sortObjectType;
sorter.SortColumn = sortcolumn;
sorter.SortingOrder = (int)sortingOrder;
InnerList.Sort(sorter);
}
}
How to use SortableCollectionBase class?
Using SortableCollectionBase
is simple and effortless. Just inherit your custom collection class from SortableCollectionBase
class and in the constructor set the SortableObjectType
property. Now your class becomes sortable.
For example
public class StudentCollection :
SortableCollectionBase
{
public StudentCollection()
{
base.SortObjectType = typeof(Student);
}
public Student this[ int index ]
{
get
{
return( (Student) List[index] );
}
set
{
List[index] = value;
}
}
public int Add( Student value )
{
return( List.Add( value ) );
}
public int IndexOf( Student value )
{
return( List.IndexOf( value ) );
}
public void Insert( int index, Student value )
{
List.Insert( index, value );
}
}
How to sort?
To sort your custom collection call the "Sort()
" method. Note: Make sure that you have set the "SortColumn
" property before calling the "Sort()
" method. "SortColumn
" is the property of the business entity based on which the collection will be sorted. In this case SortColumn
can be "name
", "id
" or "Dob
".
StudentCollection Students = new StudentCollection();
Students.Add(new Student("Sai",5,new DateTime(1914,10,4)));
Students.Add(new Student("Sree",1,new DateTime(1980,10,4)));
Students.Add(new Student("Sow",3,new DateTime(2000,4,1)));
Students.Add(new Student("Zaheer",2,new DateTime(1978,1,27)));
Students.SortColumn = "Name";
Students.SortingOrder =
GenericComparer.SortOrder.Ascending;
Students.Sort();
dataGrid1.DataSource = Students;