Saturday, March 17, 2012

Implementing IComparable Interface

As we discussed in previous posts, an interface is a contract. A class implementing an interface must implement all the signatures that are declared in this interface.

Why do you need interfaces if all they provide are the method signatures with no actual implementation? One of the reason you implement an interface is to ensure code reuse and standards. By implementing an interface, you can be virtually guaranteed that a class implementing an interface must have implemented its signatures.

For example, suppose you have a car class and a truck class, both implementing an interface IAutoMobile. IAutoMobile has a signature method called "Horsepower". Since both car and truck classes implement IAutomobile, you can be sure both classes will also implement "Horsepower" method.You can write a static method that can accept an object of type IAutoMobile and call the "Horsepower" method. Depending on the object type you passed to this method (class or truck), the code will execute the appropriate "Horsepower" and return you the information.

To see an example of this, see my previous post titled Abstraction via Interfaces - II.

While you can create and implement your own interfaces, .NET provides several interfaces that you can implement  in your classes. Today, we will discuss one such interface "IComparable".

IComparable interface provides a "CompareTo" signature that you can implement in a class to compare the two objects of this type.

Let's consider an example...

Orders Class implementing IComparable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ComparableInterface
{
    class Orders : IComparable
    {
        public int orderID { get; set; }
        public DateTime orderDate { get; set; }
        public int quantity { get; set; }
        public int customerID { get; set; }
        public Status OrderStatus { get; set; }

        //you must implement CompareTo method declared in IComparable interface

        public int CompareTo(object obj)
        {
            //cast the object to its proper type
            Orders order = obj as Orders;
            //OR
            //Orders order = (Orders)obj;
            
            if (this.orderID > order.orderID) return 1;
            else if (this.orderID < order.orderID) return -1;
            else return 0;
        }
        
    }
}


Main Method
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ComparableInterface
{
    class Program
    {
        static void Main(string[] args)
        {

            //Let's create a collection of orders and then sort them.
            List<Orders> orderlist = new List<Orders>
            {
                new Orders{orderID=100,orderDate=DateTime.Today,quantity=5,
                           customerID=10,OrderStatus=Status.placed},
                new Orders{orderID=90,orderDate=DateTime.Today,quantity=15,
                           customerID=20,OrderStatus=Status.placed}
            };
            //let's not sort it
            foreach (Orders order in orderlist)
            { Console.WriteLine("Order ID:{0}", order.orderID); }

            Console.WriteLine(Environment.NewLine);
            //now sort it
            orderlist.Sort();
            foreach (Orders order in orderlist)
            { Console.WriteLine("Order ID:{0}", order.orderID); }

            Console.Read();

         }
    }
}

Let's review the output before and after the sort. If you look closely, the output before orderlist.Sort() method is in the order objects were added to the collection, but after the Sort(), the objects are listed in ascending order based on the order ID. You may be wondering how come we didn't call the CompareTo method? Actually a Sort() method internally uses CompareTo method to compare the objects based on your implementation. Try the same example but without implementing IComparable interface and you will receive an error.

Output



The CompareTo method in the above example takes a generic object which then must be cast into a specific type. Framework provides another type safe interface "IComparable<>" which you can implement in your classes and no typecasting will be necessary.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ComparableInterface
{
    class Orders2 : IComparable<Orders2>
    {
        public int orderID { get; set; }
        public DateTime orderDate { get; set; }
        public int quantity { get; set; }
        public int customerID { get; set; }
        public Status OrderStatus { get; set; }

        //you must implement CompareTo method declared in IComparable interface

        public int CompareTo(Orders2 order)
        {
            //not casting necessary

            if (this.orderID > order.orderID) return 1;
            else if (this.orderID < order.orderID) return -1;
            else return 0;
        }
    }
}


IComparable is useful when a class implements this interface and you are comparing the same objects. CompareTo method takes another object which is of the same type and compares the current object to the passed one. But what if your class doesn't implement IComparable or if you want to compare two different objects. Framework provides another interface called IComparer. This interface defines a Compare() method that can take two objects of another type and compares them. We will look at an example of the ICompare interface in future post.

Thank you.

No comments:

Post a Comment