C# IComperable, IComparer Ara Yüzleri ve Kullanımı

IComparable interface'i uygulandığı sınıfa CompareTo adlı bir metot kazandırır ve bu metot geriye int tipinde bir değer döndürür. IComparable interface'ini sınıfımıza uygulayarak sınıfımızdan türeyen nesneleri karşılaştırılabilir hale getiririz ve böylece sıralama, karşılaştırma vb. işlemleri yapabiliriz.

// This interface allows an object to specify its
// relationship between other like objects.
public interface IComparable
{
  int CompareTo(object o);
}

Örnek olarak bir integer dizimiz olsun bunu Array sınıfının static Sort metodu ile sıralayalım:

int[] sayilar = { 4, 7, 1, 3, 2, 6, 5, 8 };
Array.Sort(sayilar);
 
foreach (int sayi in sayilar)
{
        Console.WriteLine(sayi);
}

Kodumuzu çalıştırdığımızda hatasız bir şekilde sıralı listeyi elde ederiz.

Peki bu sefer bir Car sınıfı oluşturalım ve ardından bir car dizisi oluşturup bu diziyi sıralamaya çalışalım bakalım ne olacak:

class Car
    {
        public int CarId { get; set; }
        public string Brand { get; set; }
        public string Model { get; set; }
    }
class Program
    {
        static void Main(string[] args)
        {
            Car[] carList = new Car[3];
            carList[0] = new Car() 
                { CarId = 3, Brand = "Opel", Model = "Astra" };
            carList[1] = new Car() 
                { CarId = 1, Brand = "Opel", Model = "Corsa" };
            carList[2] = new Car() 
                { CarId = 2, Brand = "Opel", Model = "Insignia" };

            Array.Sort(carList);

            foreach (Car item in carList)
            {
                Console.WriteLine("CarID: {0}, Brand: {1}, Model: {2}"
                    , item.CarId, item.Brand, item.Model);
            }
        }
    }

Bu kodu çalıştırdığımızda aşağıdaki hatayı alırız:
“Failed to compare two elements in the array.”
Çünkü dizimizi sort metoduna gönderdik fakat bu nesnenin hangi kurallara göre karşılaştırılacağını belirtmedik. Peki ilk örneğimizde de int tipinin nasıl karşılaştıracağını belirtmemiştik onda neden hata almadık? Çünkü Int32 sınıfı  IComperable interface'ini implemente etmektedir bu yüzden sayılar aritmetik sırayla sıralanmıştır. O zaman kodumuzun çalışması için bizimde Car sınıfının IComperable interface'ini implemente etmesini sağlamamız gerekiyor. Şimdi buna göre Car sınıfını yeniden yazalım :

class Car: IComparable
    {
        public int CarId { get; set; }
        public string Brand { get; set; }
        public string Model { get; set; }

        public int CompareTo(object obj)
        {
            Car temp = obj as Car;
            if (temp != null)
            {
                if (this.CarId > temp.CarId)
                    return 1;
                if (this.CarId < temp.CarId)
                    return -1;
                else
                    return 0;
            }
            else
                throw new ArgumentException("Car nesnesi degil!");
        }
    }

CompareTo Dönüş Değerlerinin Anlamları:

0'dan küçük ise : nesneden önce geliyor
0 ise : o anki nesne
0'dan büyük ise: nesneden sonra geliyor

Yukarıdaki logic'e uygun CarId property'sine göre sıralama yapan bir CompareTo metodu yazdık. Artık Array.Sort metoduna dizimizi gönderirsek CarId'ye göre sıralama yapacaktır.


Bir adım daha ileri gidelim ve düşünün ki bazen nesnenizi CarId'ye göre bazen Brand ismine göre bazende Model ismine göre sıralamanız gerekiyor. Bu durumda ne yapabiliriz? Array sınıfının static sort metodu ilk parametre olarak dizi ikinci parametre olarakta IComparer tipinde değişken alabiliyor. Yani kendi custom comparer'larımızı yazarsak bunu gerçekleştirebiliriz. Yazdığımız custom comperarımız IComparer interface'ini implemente etmesi gerekiyor ve bu implementasyon Compare metodunu sınıfımıza ekliyor. Şimdi örnek olarak Model ismine göre sıralayan comparer'ımızı yazalım:

class CarModelComparer : IComparer
    {
        public int Compare(object x, object y)
        {
            Car t1 = x as Car;
            Car t2 = y as Car;
            if (t1 != null && t2 != null)
                return String.Compare(t1.Model, t2.Model);
            else
                throw new ArgumentException("Car nesnesi degil!");
        }
    }

Bunun ardından aşağıdaki gibi sort işlemini gerçekleştirirsek:

            //Model ismine gore siralaniyor
            Array.Sort(carList, new CarModelComparer());

            foreach (Car item in carList)
            {
                Console.WriteLine("CarID: {0}, Brand: {1}, Model: {2}"
                    , item.CarId, item.Brand, item.Model);
            }

Artık foreach ile döndüğümüzde nesne örnekleri Model ismi sırasına göre gelecektir. Bu şekildeki iterasyon sonrası çıktı şu şekilde olacaktır:


İstersek sınıflarımıza IComparer tipinde property ekleyerek sınıfımıza değişik biçimlerde sort işlemi yaptıracak özellikler kazandırabiliriz. new şeklinde comparer oluşturmak yerine bunu kullanmak hem kullanım kolaylığı sağlayacaktır hemde son kullanıcı oluşturduğu nesneyi nelere göre sıralayabilecek bunu görecektir.

        public static IComparer SortByModel
        { get { return (IComparer)new CarModelComparer(); } }

        Array.Sort(carList, Car.SortByModel);

Örnek Proje : IComparableExample.rar 

0 yorum :

Yorum Gönder