ASP.NET
Network Akademi

Met Hostimg

“Bilgi paylaşıldıkça artar” sloganı ile .NET Platformuna ilişkin birikimlerin paylaşıldığı ASP.NET.TR Topluluğunda sizde “YAZAR” olmak için ; info@asp.net.tr e-mail adresine kendinizi anlatan bir e-mail göndererek başvuruda bulunabilirsiniz.

C# Generic programlama Giriş I

muammer yiğit
C#.NET
01.06.2010 12:18:33
Hit : 8315

C# Generic  programlama Giriş I

Bu makalemizde CLR 2.0’ın tanıtılması ile hayatımıza katılan generic programlamaya giriş yapacağız.  Generic programlama sayesinde en basit anlamı ile “Bir kez yaz-istediğin kadar kullan” sloganına tam destek vermiş olacağız. Yazdığımız bir kodu sadece int, double yada string türü ile çalışması yerine istediğimz tüm türler ile çalışabilmesini sağlayacağız.

CLR 2.0 öncesinde yazdığımız kodun farklı türdeki parametreler ile çalışmasını da istediğimizde zorunlu olarak Object tipini kullanıyorduk. C#’ta tüm nesneler Object türünden türediğinden dolayı object parametresine sahip olan bir methodu farklı türdeki parametreler ile çağırabiliyorduk.  Bu şekilde yazılmış bir kodda aşağıdaki sorunların oluşma ihtimali yüksekti;

·         derleme zamanında oluşabilecek tür dönüşümleri hatalarını

·         Extra tür dönüşümü maliyetleri (boxing – unboxing)

·         Yazdığımız sınıf/method kodlarını farklı türler ile kullanamama(Object tipi bir noktaya kadar farklı tiplere destek verdiğinden dolayı)

CLR 2.0’ın generic programlamayı desteklemesi ile birlikte bu gibi senaryolarda Object sınıfını kullanma zorunluluğu da ortadan kalkmış oldu.  Artık T tipini parametre alan bir generic sınıf oluşturduğumuzda, bu sınıfın kullanıldığı yerlerde çalışma zamanında karşılaşabileceğimiz tür dönüşümleri sorunlarını ya da Object türüne yapılan dönüşüm(boxing)  maliyetlerini düşünmemiz gerekmeyecektir.

Generic programlama mantığı hakkında bu kadar konuştuktan sonra, generic kullanımının bize getirecekleri inceleyelim;

Performans

            Generic programlamanın en büyük avantajlarından birisi performanstır. Generic olmayan sınıflarda kullanılan referans tiplerinin Object türüne dönüşümü(boxing) veya Object türünden referans türüne dönüşümü (unboxing) maliyetli işlemlerdir. Generic programlamada ise oluşturduğumuz sınıfa ilk aşamada hangi türde parametre alacağımızı dışarıdan belirttiğimizden dolayı tür dönüşümü maliyetlerinden otomatik olarak kurtulmuş oluyoruz.

Bu konuyu  generic olmayan ArrayList sınıfı üzerinde inceleyebiliriz. ArrayList sınıfı farklı türdeki nesneleri tek bir yerde tutmamıza olanak sağlamaktadır ve yeni bir eleman ekleyebilmemiz için Add() methodu bulunmaktadır. ArrayList’e değer tipinden(int,double vb.)  yeni bir eleman eklendiğinde eklenen eleman object türüne dönüştürülerek eklenmektedir.  Aynı şekilde ArrayList’ten okunan bir değer için ise Object türünden değer tipine dönüşüm yapılmaktadır. Örnek üzerinde inceler isek;

                ArrayList lst = new ArrayList();

                lst.Add(27);  // boxing -- değer tipinden referans tipine dönüşüm yapılıyor

                int yas = (int)lst[0]; //unboxing -- referans tipinden değer tipine dönüşüm yapılıyor

                foreach(int eleman in lst)

                {

                               Console.WriteLine(eleman);//her okunan eleman için unboxing yapılıyor

                }

 

Boxing ve unboxing kullanımı kolay olmasına rağmen performans konusunda büyük sorun oluşturmaktadır. Özellikler bir collection içerisinde iterasyon yapılıyor ise tüm elemanlar tek tek unboxing işlemine tabi tutulacaktır.

ArrayList kullanmak yerine generic yapıya sahip List<T> sınıfının kullanımı boxing ve unboxing sorununu ortadan kaldıracaktır.

      List<int> lst = new List<int>();

      lst.Add(27);      // boxing oluşmuyor.değer tipi collection’da tutuluyor

      int yas = lst[0];       // unboxing oluşmuyor.tür dönüşümüne gerek yok

      foreach (int eleman in lst)

      {

            Console.WriteLine(eleman);

      }

Tür Güvenliği

            Generic kullanımının diğer bir faydası ise tür güvenliğidir. ArrayList kullanımı ile collection’a herhangi bir türden eleman eklemesi yapılabilir.

      ArrayList lst = new ArrayList();

      lst.Add(27);

      lst.Add("herhangi bir string");

      lst.Add(new myClass());

Bu collection üzerinde foreach ile int bir eleman kullanarak iterasyon yapmaya çalışırsak, derleyici herhangi bir hata vermeyecektir.

 foreach(int eleman in lst)

{

Console.WriteLine(eleman);

}

Ancak collection’da bulunan tüm elemanlar int türünden olmadığından dolayı çalışma zamanında bir hata ile karşılaşacağız.

Generic List<T> kullanımı ile yapılacak olan hata çok daha erken fark edilebilecektir çünkü List<T> collection’ı sadece T türünden eleman eklemelerine izin verecektir ve farklı türden bir eleman eklemesinde derleyici bize uyarı verecektir.

      List<int> lst = new List<int>();//sadece int türünden elemanların tutulacağı       collection

      lst.Add(27);

      lst.Add("herhangi bir string");//tür uyumsuzluğundan dolayı HATA

      lst.Add( new myClass());//tür uyumsuzluğundan dolayı HATA

Generic Sınıf Oluşturma

Generic bir sınıf normal bir sınıfa benzer bir şekilde tanımlanmaktadır. Bunun yanında hangi tür ile kullanılacağını belirten bir generic tip tanımı içermektedir. Verdiğimiz bu generic tip ile sınıfın üyelerinin hangi tipte olacağını ve sınıfın methodlarıının parametre olarak hangi tipi kabul edeceğini belirleyebiliriz. Aşağıdaki örnekte bu özelliği görebiliriz;

    public class myGenericPair<T> //<T> generic tip tanımı yapmaktadır.

    {

        private T genericMember;//generic üye

        private int value;//generic olmayan üye

       

        //Consttructor

        public myGenericPair(T genericMember, int value)

        {

            this.genericMember = genericMember;

            this.yas = value;

        }

 

        //generic bir türde dönüş değerine sahip method

        public T getGenericValue()

        {

            return genericMember;

        }

    }

Oluşturduğumuz sınıfı ise şu şekilde kullanabiliriz;

            myGenericPair<string> genericSinifim = new myGenericPair<string>("Ali Can",5);

            genericSinifim.getGenericValue();

Görüldüğü gibi <T> yerine sınıfı hangi generic açılımını kullanacak isek T türünde onu belirtiyoruz.Üstteki örnekte myGenericPair sınıfının string açılımı kullanılmıştır.

 

Generic Sınıfların Özellikleri

 

generic sınıflar kullanılır iken bazı koşullara ihtiyaç duyabiliriz. Örneğin generic bir tipe null değeri atamak mümkün değildir. Bunu yapabilmek için “default” anahtar kelimesi kullanılabilir ya da kullanılacak olan generic tipin bazı özelliklere sahip olmasını istediğimiz durumlarda (T tipinin belirli bir interface’i uygulaması istediğimizde ya da T tipini belirli bir türden türemesini istediğmizde) sınırlandırmalar kullanılabilir.

Default anahtar kelimesi(null değer atama)

 

Defult anahtar kelimesi en basit tanımı ile T türüne 0( T değer türü ise) ya da “null”(T referans türü ise) atamakta kullanılır. Örneğin bir banka otomasyonu yapan bir programda sıradaki müşteriler içerisinden bir müşteriyi geri döndüren bir methoda sahip olduğumuzu düşünelim. Eğer kuyrukta müşteri yok ise null değeri döndürülsün.

        public T getNextCustomer()

        {

            T musteri = default(T);

            T = kuyruk.Dequeue();

            return T;

        }

Kısıtlamalar

 Generic sınıfımızda kullanılacak T  tipiniz bazı koşulları sağlaması istediğimiz durumlarda kısıtlamalar çok faydalı olacaktır. Örneğin T tipinin değer tipi olmasını istediğiz aşağıdaki gibi bir kısıtlama yazmamız yeterli olacaktır.

    public class myGeneric<T, U>

            where T : struct // T parametresi değer tipinde olmalı

            where U : class  // U parametresi referans tipinde olmalı

 

    {….}

 

 

 

Aşağıdaki tabloda  6 tipte yapılabilen kıstılamalar bulunuyor;

Kıstılama

Tanım

where T : struct

T tipi değer tipinde olmalı.(Nullable dışındaki tüm değer tipleri olabilir)

where T : class

T tipi referans tipinde olmalı

where T : new()

T tipi public parametresiz constructor’a sahip olmalı

where T : <temel sınıf adı>

T tipi belirli bir sınıftan türemeli

where T : <interface adi>

T tipi belirli bir interface’i uygulamalı

where T : U

T tipi U tipinden türemeli ya da U tipinde olmalı

 

Static Üyeler

Generic sınıflarda static üyelere özellikle dikkat edilmeli. Çünkü T tipine göre oluşan her sınıfın static üyeleri sadece kendi aralarında paylaşılır.

Yani myClass<string> ile myClass<int> açılımlarının static üyeleri birbirinden farklı değerlere sahiptir. Örneğin;

      public class myClass<T>

      {

                  public static int x;

      }

 

      myClass<string>.x = 5;

      myClass<int>.x = 7;

      Console.WriteLine(myClass<string>.x);//Console 5 yazılıyor

 

Sonraki makalemde generic methodlar,Interface,delegateler konuları inceleceğim. Başka bir makalede görüşmek üzere…

 

 




BU İÇERİĞE YORUMDA BULUNUN


Bu MAKALE'ye yorum yapabilmek için Üye olmalısınız ...!


BU İÇERİĞE YAPILAN YORUMLAR