Jul 23 Tommy | CodeBits

CodeBits: Using IComparer with Generics Collection

.Net is a really cool language. Two things I love about them are Generics and Collections. Now I will combine them and enhance it with IComparer and reflection to create the collection to end all collections. First we will create a generic collections class. Here is our collection:

public class DataCollection : CollectionBase
{
    public virtual T this[int index]
    {
        get { return (T)this.List[index]; }
        set { this.List[index] = value; }
    } 

    public virtual int IndexOf(T item)
    {
        return this.List.IndexOf(item);
    }

    public virtual int Add(T item)
    {
        return this.List.Add(item);
    }

    public virtual void Remove(T item)
    {
        this.List.Remove(item);
    }
 
    public virtual void CopyTo(Array array, int index)
    {
        this.List.CopyTo(array, index);
    }

    public virtual void AddRange(DataCollection collection)
    {
        this.InnerList.AddRange(collection);
    } 

    public virtual void AddRange(T[] collection)
    {
        this.InnerList.AddRange(collection);
    }

    public virtual bool Contains(T item)
    {
        return this.List.Contains(item);
    }

    public virtual void Insert(int index, T item)
    {
        this.List.Insert(index, item);
    }
}

Next we will add a general function to use for sorting objects in our collection.

*Note that this code is part of the collection class.

public void Sort(string sortExpression, SortDirection sortDirection)
{            
    if (_SortField == sortExpression)
    {                
        if (_SortDirection == SortDirection.Ascending)
        {
            _SortDirection = SortDirection.Descending;
        }
        else
        {
            _SortDirection = SortDirection.Ascending;
        }
    }
    else
    {
        _SortDirection = sortDirection;
        _SortField = sortExpression;
    }

    InnerList.Sort(new Comparer(_SortField, _SortDirection));
}

public void Sort(string sortExpression)
{
    _SortDirection = SortDirection.Ascending;            
    _SortField = sortExpression;
    InnerList.Sort(new Comparer(sortExpression));
}

private SortDirection _SortDirection = SortDirection.Ascending;
private String _SortField = string.Empty;

public SortDirection GetSortDirection { get { return _SortDirection; } }
public String GetSortField { get { return _SortField; } }

 

I have seen many sites have a collection like this. Then they implement an IComparer for each object in a collection so that you can sort the collection based on an member of the object in the collection. This is good if you were building something like a Data Access Layer for your application. However these require strong typed collections and objects. That would require a lot of coping and pasting if we wanted to implement an IComparer for each member of the object class. Or we can just use reflection and have one IComparer for all class members.

* Note that this code is a seperate class

public class Comparer : IComparer
{
    string m_SortPropertyName;
    SortDirection m_SortDirection;
    int direction;

    public Comparer(string sortPropertyName)
    {
        this.m_SortPropertyName = sortPropertyName;
        this.m_SortDirection = SortDirection.Ascending;
        direction = -1;
        // default to ascending order
    }

    public Comparer(string sortPropertyName, SortDirection sortDirection)
    {
        this.m_SortPropertyName = sortPropertyName;
        this.m_SortDirection = sortDirection;
        direction = -1;

        if (sortDirection == SortDirection.Descending) { direction = 1; }
    }
 
    public int Compare(object x, object y)
    {

        // Get the values of the relevant property on the x and y objects

        object valueOfX = x.GetType().GetProperty(m_SortPropertyName).GetValue(x, null);
        object valueOfY = y.GetType().GetProperty(m_SortPropertyName).GetValue(y, null);

        IComparable comp = valueOfY as IComparable;

        // Flip the value from whatever it was to the opposite so it sorts correctly.

        return Flip(comp.CompareTo(valueOfX));
    }

 
    private int Flip(int i)
    {
        return (i * direction);
    }
}

 

Now I know whare you are thinking. What would you do with this? Simple:

public void Test
{

    DataCollection collection = new DataCollection();
    //fill collection with dataset here.

    collection.Sort((fieldNameString), SortDirection)
}

 

We can now sort any collection of objects on any member of that object. There is something I like about not having to ever write another collection or sort function ever again, period.

DataCollection.cs

Comments are closed

About

Mooglegiant.net is a site maintained by me (mooglegiant).  I occasionally put together blogengine.net themes, and random posts about tech/geek things.  If you like the site, or my work, don't forget to support me.  I'm sure you know where to click.