C# 2.0 ile birlikte gelen bir özelliktir. LINQ kütüphanesinde, Linq To Sql veya Entity Framework gibi ORM araçlarında ve koleksiyonlarda sıkça kullanılmaktadır. Generic olmak ; tasarım anında tipin belli olmamasıdır. Bu yazıda, generic sınıfları inceleyeceğiz.
Örnek bir Generic sınıf tasarımı yapalım.
class GenericSinif<T>
{
public void Test(T paramtere)
{
Console.WriteLine("{0}", paramtere.ToString());
}
}
Sınıfın ismini yazarken, yanına köşeli parantezlerle yazdığımız tiplere “generic type argument” deriz. Örneğimizde bir tane yazdık. Virgüller ile birden fazla argüman da yazabiliriz. ( class GenericSinif<T,K,L,M> )
Şimdi bu sınıfın nesnesini üretelim ve non-static olan Test metodunu bu nesne üzerinden çağıralım.
class Program
{
static void Main(string[] args)
{
GenericSinif<int> sayi = new GenericSinif<int>();
sayi.Test(15);
}
}
GenericSinif nesnesi üretirken köşeli parantezler içine int yazdığımız için, çalışma anında bu sınıf içerisindeki T tipleri int olarak muamele göreceklerdir. T’nin ne olduğu tasarım anında değil, o sınıfın nesnesini ürettiğimiz anda belli olmaktadır.
Şimdi de .Net framework içerisinden örnekler verelim. ArrayList sınıfını göz önünde bulunduralım. Bildiğiniz gibi ArrayList, her tip nesneyi bir arada tutabilen bir koleksiyondur. ArrayList nesnesi oluşturduğumuz zaman, arka tarafta compiler tarafından bir adet 4 elemanlı object dizisi oluşturulur. Dizi doldukça da bu sayı 8,16,32 olarak artar. Yani içeride tutulan elemanlar object tipindedir. Dolayısıyla içeriden bir elemanı okumaya kalktığımız zaman cast etmek zorunda kalırız. Halbuki çoğunlukla, koleksiyonlar içerisinde aynı tipten nesneler tutarız. Yani ArrayList bize gereğinden fazla özgürlük tanır. Ancak iyi programcı, kod yazarken her zaman en kısıtlı olanı kullanmalıdır.
İçerisinde stringler olan bir koleksiyona ihtiyacımız olduğunu düşünelim. İlk olarak ArrayList üzerinden gidelim. Elimizde 10 tane şehir adı olsun ve bunları Bir ArrayList’e eklemeye çalıştığımızı varsayalım. Add metodu ile bu stringleri eklerken, yanlışlıkla bir elemanı tek tırnak içerisinde yazdığımızı düşünelim. Daha sonra bir döngü ile bu koleksiyonda gezip nesneleri okurken, string’e cast ederek okuma yapmamız gerekecek ve yaptığımız hata derleme zamanında değil, çalışma zamanında ortaya çıkacak. İşte bu gibi sorunların önüne geçebilmek için burada ArrayList yerine List<T> koleksiyonunu kullanmalıyız. Kullanım olarak ArrayList ile aynıdırlar. Tek farkı, tipin tasarım anında değil de nesne üretilirken belli olmasıdır. Yani bir List<T> nesnesi oluştururken T yerine hangi tipi yazarsak, koleksiyonumuz o tipten nesneleri tutabilir hale gelecektir.
class Program
{
static void Main(string[] args)
{
List<string> sehirler = new List<string>();
sehirler.Add("istanbul");
sehirler.Add("Ankara");
sehirler.Add("İzmir");
//....
}
}
Bu sayede artık sehirler koleksiyonumuza string olmayan bir nesne eklemeye kalktığımızda derleme zamanı hatası alacağız.
Şimdi de kod yazarak Generic bir koleksiyon oluşturmaya çalışalım.
class BizimKoleksiyon<T>
{
T[] _dizi;
public BizimKoleksiyon()
{
_dizi = new T[4];
}
public void ElemanEkle(T eleman)
{
for (int i = 0; i < _dizi.Length; i++)
{
if (_dizi[i] == null)
{
_dizi[i] = eleman;
break;
}
}
}
}
ArrayListin çalışma mantığı ile aynı olan basit bir örnek tasarım yapmış olduk. Şimdi de oluşturduğumuz sınıfın nesnesini üretip eleman eklemeye çalışalım.
class Program
{
static void Main(string[] args)
{
BizimKoleksiyon<string> bk = new BizimKoleksiyon<string>();
bk.ElemanEkle("istanbul");
bk.ElemanEkle("izmir");
bk.ElemanEkle("ankara");
bk.ElemanEkle("bursa");
}
}
BizimKoleksiyon adlı sınıfa ElemanOkuma, Dizi boyutunu artırma, indexer vs gibi birçok özellik de ekleyebiliriz.
7 yorum:
Geri dönüş tipi de generic olabilir mi?
Örnek?
Generic tipler tabiki de dönüş tipi olarak kullanılabilir. Enumerable sınıfında yer alan LINQ metotlarının çoğu geriye generic tipler dönmektedir.
Geri dönüş tipi IEnumerable olan bir metot düşünelim. Bunun anlamı, içerisinde integer tipinden nesneler olan ve iterasyon yapılabilir bir nesnedir. Bu nesne üzerinden tekrardan LINQ metotları çağırılabilir..
Peki BizimKoleksiyon içerisine eklediğimiz elemanları ekrana nasıl yazdıracağız? Foreach kullanımını anlatabilir misiniz?
Merhaba,
_dizi değişkenin public yapmamız gerek yok aslında. Amaç arka tarafta private bir dizi saklamak zaten. Aşağıdaki gibi yapılabilir
public T[] _dizi;
public void EkranaYaz()
{
foreach (var item in _dizi)
{
Console.WriteLine(item);
}
}
Main metodu icinde de:
BizimKoleksiyon bk = new BizimKoleksiyon();
bk.ElemanEkle("....");
bk.ElemanEkle("----");
bk.ElemanEkle("****");
bk.EkranaYaz();
Ya da BizimKoleksiyon adlı sınıfa, foreach ile iterasyon yapma yeteneği kazandırılabilir. Bunun için IEnumerable interface'i kullanılmalıdır.
Bakınız : http://onursalkaya.blogspot.com/2011/09/c-foreach-iterasyonu.html
BizimKoleksiyon bizim= new BizimKoleksiyon();
int tipinde tanımlama yaptığımız zaman , int array oluşturuluğunda default değerler 0 atanmakta ve ekleme işlemi yapıldığında " if (_dizi[i] == null)" kontrolü işlemeyeceğinde diziye atama yapılamıyor
Sorunu ;
class BizimKoleksiyon
{
List list;
public BizimKoleksiyon()
{
list = new List();
}
public void ElemanEkle(T eleman)
{
list.Add(eleman);
}
}
Bu şekilde yaparak çözdüm ama array olarak yapmak istesem nasıl olurdu yardımcı olursanız çok teşekkür ederim
Yorum Gönder