27 Ekim 2011 Perşembe

C# Generic Metot

Önceki makalelerimden birinde generic kavramının ne olduğundan olduğundan kısaca bahsetmiştim. Bugün de bir metodu nasıl generic hale getireceğimizi inceleyeceğiz. Asıl düşünülmesi gereken nokta nasıl değil, neden yapmamız gerektiğidir.

Bildiğiniz gibi ArrayList sınıfı arka tarafta bir object dizisi örnekler ve başlangıçta boyutu 4’dür. ArrayList’e elemanlar ekledikçte arka taraftaki bu object dizisinin boyutu ihtiyaç oldukça iki katına çıkartırılır.

Arka taraftaki dizi boyutlandırma işlemini manuel olarak yapmaya çalışalım. DiziBoyutlandır diye bir metodumuz olsun. Parametre olarak bir dizinin referansını alsın ve geriye void döndürsün.

NOT: Parametreyi referans olarak geçtiğimiz için, yaptığımız değişiklik metodu çağırırken parametre olarak verilen işaretçi üzerinde gerçekleşecektir.

class Program

    {

        static void DiziBoyutlandir(ref int[] dizi)

        {

            int[] boyutlandirilmisDizi = new int[dizi.Length * 2]; //parametre olarak gelen dizinin 2 katı boyutuna sahip yeni bir dizi ürettik.

            for (int i = 0; i < dizi.Length; i++)

            {

                boyutlandirilmisDizi[i] = dizi[i]; //parametre olarak gelen dizi içerisindeki elemanları yeni oluşturduğumuz diziye ekliyoruz.

            }

 

            dizi = boyutlandirilmisDizi; //dizi adlı işaretçi Main metodu içerisindeki 'sayilar' değişkenini temsil etmektedir. Dolayısı ile 'sayilar'değişkeni artık yeni oluşturulan diziyi işaret edecek.

        }

 

        static void Main(string[] args)

        {

            int[] sayilar = { 1, 2, 3, 4 };

            foreach (int sayi in sayilar)

            {

                Console.WriteLine(sayi);

            }

 

            Console.WriteLine("******************************************");

 

            DiziBoyutlandir(ref sayilar);

            foreach (int sayi in sayilar)

            {

                Console.WriteLine(sayi);

            }

        }

    }

Main metodu içerisinde oluşturduğumuz sayilar adlı 4 elemanlı dizinin elemanlarını ekrana yazdırıyoruz. Ardından diziyi yeniden boyutlandırarak, elemanları tekrar ekrana yazdırıyoruz. Ekran çıktısı aşağıdaki gibi olacaktır.

image

Dizimizin yeniden boyutlandırılmış halini ekrana yazdırdığımızda 8 elemanlı olduğunu ve sondaki 4 elemana integer tipinin default değeri olan 0’ın atandığını görürüz.

Şimdi de double tipinden bir diziyi boyutlandıran metoda ihtiyacımız olduğunu varsayalım. DiziBoyutlandir adlı metodu overload edelim.

static void DiziBoyutlandir(ref double[] dizi)

        {

            double[] boyutlandirilmisDizi = new double[dizi.Length * 2];

           

            for (int i = 0; i < dizi.Length; i++)

            {

                boyutlandirilmisDizi[i] = dizi[i];

            }

 

            dizi = boyutlandirilmisDizi;

        }

Byte dizisini boyutlandıran bir metoda ihtiyacımız olduğunu varsayarsak aynı metodu 2.kez aşırı yükleyebiliriz.

static void DiziBoyutlandir(ref byte[] dizi)

        {

            byte[] boyutlandirilmisDizi = new byte[dizi.Length * 2];

           

            for (int i = 0; i < dizi.Length; i++)

            {

                boyutlandirilmisDizi[i] = dizi[i];

            }

 

            dizi = boyutlandirilmisDizi;

        }

Farkettiğiniz üzere, aynı işlemi birden fazla kez tekrarlamış olduk. Metotların yaptığı işler birebir aynı olmasına rağmen tek fark, farklı bir tip ile işlem yapılmasıdır. İşte bu noktada generic kavramı devreye girmektedir. Biz int, double veya byte değil de T tipinden bir dizi için generic bir metot yazarsak, tüm tipler için istediğimiz işlemi gerçekleştiren bir metoda sahip oluruz.

static void DiziBoyutlandir<T>(ref T[] dizi)

        {

            T[] boyutlandirilmisDizi = new T[dizi.Length * 2];

 

            for (int i = 0; i < dizi.Length; i++)

            {

                boyutlandirilmisDizi[i] = dizi[i];

            }

 

            dizi = boyutlandirilmisDizi;

        }

Artık herhangi bir tipten verilen bir diziyi boyutlandırabilecek bir metoda sahibiz. Bir metot yazıp defalarca aşırı yüklemek yerine, tek bir metot ile amacımızı gerçekleştirmiş olduk.

Daha önceki makalelerimden birinde Generic tipler ile ilgili bazı kısıtlamalardan bahsetmiştim. Aynı kısıtlamaları generic metotlara uygulayabilmemiz de mümkündür. Mesela DiziBoyutlandir metodundaki T tipinin yalnızca sayısal tipler olabileceğini vurgulayabiliriz. Bunun için yapmamız gereken “where” anahtar sözcüğü ile gerekli kısıtı belirtmektir.

static void DiziBoyutlandir<T>(ref T[] dizi) where T : struct

        {

            T[] boyutlandirilmisDizi = new T[dizi.Length * 2];

 

            for (int i = 0; i < dizi.Length; i++)

            {

                boyutlandirilmisDizi[i] = dizi[i];

            }

 

            dizi = boyutlandirilmisDizi;

        }

Bu durumda T yerine referans türlü bir tip gönderirsek derleme zamanında hata alacağız. Örneğin, metodu çağırırken parametre olarak string tipinden bir dizi  gönderirsek aşağıdaki gibi bir hata mesajı ile karşılaşacağız.

The type 'string' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'GenericMetot.Program.DiziBoyutlandir<T>(ref T[])'  

Son olarak, yazdığımız generic metodu Main metodu içerisinde test edelim.

static void Main(string[] args)

        {

            Console.WriteLine("Integer dizisi için...");

 

            int[] sayilar = { 1, 2, 3, 4 };

            foreach (int sayi in sayilar)

            {

                Console.WriteLine(sayi);

            }

 

            Console.WriteLine("******************************************");

 

            DiziBoyutlandir(ref sayilar); // T tipi çalışma anında int olarak davranacak

            foreach (int sayi in sayilar)

            {

                Console.WriteLine(sayi);

            }

 

            Console.WriteLine();

            Console.WriteLine("Double dizisi için");

 

            double[] ondalikSayilar = { 1.4, 5.76, 3.9, 10.5 };

 

            foreach (double sayi in ondalikSayilar)

            {

                Console.WriteLine(sayi);

            }

 

            Console.WriteLine("******************************************");

 

            DiziBoyutlandir(ref ondalikSayilar);  // T tipi çalışma anında double olarak davranacak

            foreach (double sayi in ondalikSayilar)

            {

                Console.WriteLine(sayi);

            }

        }

Alacağımız ekran görüntüsü ise aşağıdaki gibi olacaktır.

image



2 yorum:

Adsız dedi ki...

teşekkürler.

husam dedi ki...

Teşekkür ederim.

Yorum Gönder