Tuesday, August 24, 2010

Don't get caught up with IComparable and IComparer, just implement it.

IComparable and IComparer sounds similar but don't get caught up by their name, even though they have similar names they serve different purpose.
If we want to have an ability of sorting or comparison capability for our custom objects, then we must impelment either or both of these interfaces.

Lets start by creating an object called "Employee" and add them to a list called employees.

class Employee
    {
        public string Name { get; set; }
        public int Id { get; set; }  
    }

static void Main(string[] args)
        {
            var employees = new List<Employee>();
            employees.Add(new Employee { Id = 6666, Name = "Jack" });
            employees.Add(new Employee { Id = 1111, Name = "John" });
            employees.Add(new Employee { Id = 2222, Name = "David" });
        }

Now, if your try to sort this by
employees.Sort() then you will get and exception :


InvalidOperationException was unhandled
"Failed to compare two elements in the array."
Inner Exception : {"At least one object must implement IComparable."}

In other words, the error is asking us what we mean by sorting employees.
 Well, it is clear from the exception that we need to implement the IComparable interface to be able to sort the employees list.
IComparable is used for comparing two objects of a particular type. It can be thought of as default sort provider for our objects.
Hence, we implment the IComparable as follows :
class Employee : IComparable
    {
        public string Name { get; set; }
        public int Id { get; set; }

        // Implement IComparable CompareTo method - provide default sort order.
        int IComparable.CompareTo(object obj)
        {
            Employee c = (Employee)obj;
            return String.Compare(this.Name, c.Name);

        }
    }

The IComparable requires the implementation of a method called CompareTo.

Now if you do
employees.Sort() , it will sort based on the Name.
ICompares is similar to IComparable but it can provide additional comparison mechanisms. We may want to sort our list in descending / ascending order or may want to order our object based on several fields or properties, it is all achieveable by using IComparer.

IComparer requires the implementation of the method called Compare and takes two parameters. They are two objects we are going to compare.

We can implement IComparer as follows :
class EmployeeComparer : IComparer<Employee>
    {     
        public int Compare(Employee emp1, Employee emp2)
        {
            if (emp1 == null & emp2 == null)
            {
                return 0;
            }
            else if (emp1 == null)
            {
                return -1;
            }
            else if (emp2 == null)
            {
                return 1;
            }
            else if (emp1.Id < emp2.Id)
            {
                return -1;
            }
            else if (emp1.Id == emp2.Id)
            {
                return 0;
            }
            else
            {
                return 1;
            }
        }
    }


Once you have implmented the IComparer you will be able to use
employees.Sort(new EmployeeComparer());   to do you comparison.
References

http://www.aspfree.com/c/a/C-Sharp/Building-Csharp-Comparable-Objects-IComparable-versus-IComparer/2/
http://support.microsoft.com/kb/320727
http://codebetter.com/blogs/david.hayden/archive/2005/03/06/56584.aspx
http://dpatrickcaldwell.blogspot.com/2009/03/implementing-icomparer-in-c.html
http://www.c-sharpcorner.com/uploadfile/camurphy/csharplists03302006170209pm/csharplists.aspx

No comments:

Post a Comment