C#’ta Hashtable Koleksiyon Sınıfının Kullanımı
Hashtable Koleksiyon Sınıfının Kullanımı
Bu makalemizde HashTable koleksiyon sınıfını incelemeye çalışacağız. Bildiğiniz gibi Koleksiyonlar System.Collections namespace’inde yer almakta olup, birbirlerinin aynı veya birbirlerinden farklı veri tiplerinin bir arada tutulmasını sağlayan diziler oluşturmamıza imkan sağlamaktadırlar. Pek çok koleksiyon sınıfı vardır. Bugün bu koleksiyon sınıflarından birisi olan HashTable koleksiyon sınıfını inceleyeceğiz.
HashTable koleksiyon sınıfında veriler key-value dediğimiz anahtar-değer çiftleri şeklinde tutulmaktadırlar. Tüm koleksiyon sınıflarının ortak özelliği barındırdıkları verileri object tipinde olmalarıdır. Bu nedenle, HashTable’lardada key ve value değerleri herhangibir veri tipinde olabilirler. Temel olarak bunların her biri birer DictionaryEntry nesnesidir. Bahsetmiş olduğumuz key-value çiftleri hash tablosu adı verilen bir tabloda saklanırlar. Bu değer çiftlerine erişmek için kullanılan bir takım karmaşık kodlar vardır.
Key değerleri tektir ve değiştirilemezler. Yani bir key-value çiftini koleksiyonumuza eklediğimizde, bu değer çiftinin value değerini değiştirebilirken, key değerini değiştiremeyiz. Ayrıca key değerleri benzersiz olduklarında tam anlamıyla birer anahtar alan vazifesi görürler. Diğer yandan value değerline null değerler atayabilirken, anahtar alan niteliğindeki Key değerlerine null değerler atayamayız. Şayet uygulamamızda varolan bir Key değerini eklemek istersek ArgumentException istisnası ile karşılaşırız.
HashTable koleksiyonu verilere hızı bir biçimde ulaşmamızı sağlayan bir kodlama yapısına sahiptir. Bu nedenle özellikle arama maliyetlerini düşürdüğü için tercih edilmektedir. Şimdi konuyu daha iyi pekiştirebilmek amacıyla, hemen basit bir uygulama geliştirelim. Uygulamamızda, bir HastTable koleksiyonuna key-value çiftleri ekliyecek, belirtilen key’in sahip olduğu değere bakılacak, tüm HashTable’ın içerdiği key-value çiftleri listelenecek, eleman çiftlerini HashTable’dan çıkartacak vb… işlemler gerçekleştireceğiz. Form tasarımını ben aşağıdaki şekildeki gibi yaptım. Temel olarak teknik terimlerin türkçe karşılığına dair minik bir sözüğü bir HashTable olarak tasarlayacağız.
Şekil 1. Form Tasarımımız.
Şimdi kodlarımıza bir göz atalım.
| System.Collections.Hashtable htTeknikSozluk; /* HashTable koleksiyon nesnemizi tanimliyoruz.*/
private void Form1_Load(object sender, System.EventArgs e) private void btnEkle_Click(object sender, System.EventArgs e) private void lstAnahtar_DoubleClick(object sender, System.EventArgs e) deger=htTeknikSozluk[lstAnahtar.SelectedItem.ToString()].ToString(); /* HashTable’daki bir degere ulasmak için, köseli parantezler arasinda aranacak key degerini giriyoruz. Sonucu bir string degiskenine aktariyoruz.*/ MessageBox.Show(deger,lstAnahtar.SelectedItem.ToString()); private void btnSil_Click(object sender, System.EventArgs e) lstAnahtar.Items.Remove(lstAnahtar.SelectedItem); stbDurum.Text=”Çikartildi”; stbDurum.Text=htTeknikSozluk.Count.ToString(); private void btnTumu_Click(object sender, System.EventArgs e) ICollection anahtar=htTeknikSozluk.Keys; foreach(string a in anahtar) |
Şimdi uygulamamızı çalıştıralım.
Şekil 2. Programın Çalışmasnının sonucu.
Geldik bir makalemizin daha sonuna. Bir sonraki makalemizde görüşmek dieğiyle hepinize mutlu günler dilerim.
Stack ve Queue Koleksiyon Sınıfları
Bu makalemizde Stack ve Queue koleksiyon sınıflarını incelemeye çalışacağız. Bir önceki makalemizde bildiğiniz gibi, HashTable koleksiyon sınıfını incelemeştik. Stack ve Queue koleksiyonlarıda, System.Collections isim alanında yer alan ve ortak koleksiyon özelliklerine sahip sınıflardır.
Stack ve Queue koleksiyonları, her koleksiyon sınıfında olduğu gibi, elemanlarını object tipinde tutmaktadırlar. Bu koleksiyonların özelliği giren-çıkan eleman prensibleri üzerine çaılşmalarıdır. Stack koleksiyon sınıfi, LIFO adı verilen, Last In First Out( Son giren ilk çikar) prensibine gore çalışırken, Queue koleksiyon sınıfı FIFO yani First In First Out(ilk giren ilk çıkar) prensibine gore çalışır. Konuyu daha iyi anlayabilmek için asağıdaki şekilleri göz önüne alalım.
Sekil 1. Stack Koleksiyon Sınıfının Çalışma Yapısı
Görüldüğü gibi, Stack koleksiyonunda yer alan elemanlardan son girene ulaşmak oldukça kolaydır. Oysaki ilk girdiğimiz elemana ulaşmak için, bu elemanın üstünde yer alan diğer tüm elemanları silmemiz gerekmektedir. Queue koleksyion sınıfına gelince;
Sekil 2. Queue Koleksiyon Sınıfının Çalışma Yapısı
Görüldügü gibi Queue koleksiyon sinifinda elemanlar koleksiyona arkadan katilirlar ve ilk giren eleman kuyruktan ilk çikan eleman olur.
Stack ve Queue farklı yapılarda tasarlandıkları için elemanlarına farklı metodlar ile ulaşılmaktadır. Stack koleksiyon sınıfında, en son giren elemanı elde etmek için Pop metodu kullanılır. Koleksiyona bir eleman eklerken Push metodu kullanılır. Elbette eklenen eleman en son elemandır ve Pop metodu çağrıldığında elde edilecek olan ilk eleman halini alir. Ancak Pop metodu son giren elemanı verirken bu elemanı koleksiyondan siler. İşte bunun önüne geçen metod Peek metodudur. Şimdi diyebilirsiniz ki madem son giren elemanı siliniyor, Pop metodunu o zaman niye kullanıyoruz. Hatırlarsanız, Stack koleksiyonunda, ilk giren elemanı elde etmek için bu elemanın üstünde yer alan tüm elemanları silmemiz gerektiğini söylemiştik. İşte bir döngü yapısında Pop metodu kullanıldığında, ilk giren elemana kadar inebiliriz. Tabi diğer elemanlari kaybettikten sonra bunun çok büyük önem taşıyan bir eleman olmasını da istemiş olabiliriz.
Gelelim Queue koleksiyon sınıfının metodlarına. Dequeue metodu ile koleksiyona ilk giren elemani elde ederiz. Ve bunu yaptığımız anda eleman silinir. Nitekim dequeue metodu pop metodu gibi çalışır. Koleksiyona eleman eklemek için ise, Enqueue metodu kullanılır. İlk giren elemanı elde etmek ve silinmemesini sağlamak istiyorsak yine stack koleksiyon sınıfinda olduğu gibi, Peek metodunu kullanırız.
Bu koleksiyonlarin en güzel yanlarından birisi siz eleman sayısını belirtmediğiniz takdirde koleksiyonun boyutunu otomatik olarak kendilerinin ayarlamalarıdır. Stack koleksiyon sınıfı, varsayilan olarak 10 elemanlı bir koleksiyon dizisi oluşturur.(Eğer biz eleman sayısını yapıcı metodumuzda belirtmez isek).Eğer eleman sayısı 10’u geçerse, koleksiyon dizisinin boyutu otomatik olarak iki katina çıkar. Ayni prensip queue koleksiyon sinifi içinde geçerli olmakla birlikte, queue koleksiyonu için varsayilan dizi boyutu 32 elemanli bir dizidir.
Simdi dilerseniz, basit bir console uygulamasi ile bu konuyu anlamaya çalisalim.
| using System; using System.Collections; /* Uygulamalarimizda koleksiyon siniflarini kullanabilmek için Collections isim uzayini kullanmamiz gerekir.*/ namespace StackSample1 static void Main(string[] args) stc.Push(“Burak”); /*Eleman eklemek için Push metodu kullaniliyor.*/ Console.WriteLine(“Çikan eleman {0}”,stc.Pop().ToString());/* Pop metodu son giren(kalan) elemani verirken, ayni zamanda bu elemani koleksiyon dizisinden siler.*/ while(dizi.MoveNext()) /* dizi nesnesinde okunacak bir sonraki eleman var oldugu sürece isleyecek bir döngü.*/ Console.WriteLine(“——————“); dizi=stc.GetEnumerator(); while(dizi.MoveNext()) } |
3. Stack ile ilgili programın ekran çıktısı
Queue örnegimiz ise aynı kodlardan oluşuyor sadece metod isimleri farklı.
| using System; using System.Collections; namespace QueueSample1 qu.Enqueue(“Burak”); /*Eleman eklemek için Enqueue metodu kullaniliyor.*/ Console.WriteLine(“Çikan eleman {0}”,qu.Dequeue().ToString());/* Dequeue metodu ilk giren(en alttaki) elemani verirken, ayni zamanda bu elemani koleksiyon dizisinden siler.*/ IEnumerator dizi=qu.GetEnumerator(); /* Koleksiyonin elemanlarini IEnumerator arayüzünden bir nesneye aktariyoruz.*/ Console.WriteLine(“——————“); dizi=qu.GetEnumerator(); while(dizi.MoveNext()) } |
Sekil 4. Queue ile ilgili programin ekran çıktısı
Geldik bir makalemizin daha sonuna. Umuyorumki sizlere faydalı olabilecek bilgiler sunabilmişimdir. Bir sonraki makalemizde görüsmek dileğiyle hepinize mutlu günler dilerim.
Reflection(Yansıma) ile Tiplerin Sırrı Ortaya Çıkıyor
Hiç dotNET ‘te yer alan bir tipin üyelerini öğrenebilmek istediniz mi? Örneğin var olan bir dotNET sınıfının veya sizin kendi yazmış olduğunuz yada bir başkasının yazdığı sınıfa ait tüm üyelerin neler olduğuna programatik olarak bakmak istediniz mi?
İşte bugünkü makalemizin konusu bu. Herhangi bir tipe (type) ait üyelerin neler olduğunu anlayabilmek. Bu amaçla, Reflection isim uzayını ve bu uzaya ait sınıfları kullanacağız. Bildiğiniz gibi .NET ‘te kullanılan her şey bir tipe aittir. Yani herşeyin bir tipi vardır. Üyelerini öğrenmek isteğimiz bir tipi öncelikle bir Type değişkeni olarak alırız. (Yani tipin tipini alırız. Bu nedenle ben bu tekniğe Tip-i-Tip adını verdim ). Bu noktadan sonra Reflection uzayına ait sınıfları ve metodlarını kullanarak ilgili tipe ait tüm bilgileri edinebiliriz. Küçük bir Console uygulaması ile konuyu daha iyi anlamaya çalışalım. Bu örneğimizde, System.Int32 sınıfına ait üyelerin bir listesini alacağız. İşte kodlarımız;
| using System; namespace ReflectionSample1 { class Class1 { static void Main(string[] args) { Type tipimiz=Type.GetType(“System.Int32″);/* Öncelikle String sinifinin tipini ögreniyoruz. */ System.Reflection.MemberInfo[] tipUyeleri=tipimiz.GetMembers(); /* Bu satir ile, System.String tipi içinde yer alana üyelerin listesini Reflection uzayinda yer alan, MemberInfo sinifi tipinden bir diziye aktariyoruz. */ Console.WriteLine(tipimiz.Name.ToString()+” sinifindaki üye sayisi:”+tipUyeleri.Length.ToString());/* Length özelligi, MemeberInfo tipindeki dizimizde yer alan üyelerin sayisini, (dolayisiyla System.String sinifi içinde yer alan üyelerin sayisini) veriyor.*/ /* Izleyen döngü ile, MemberInfo dizininde yer alan üyelerin birtakim bilgilerini ekrana yaziyoruz.*/ |
Uygulamayı çalıştırdığımızda aşağıdaki ekran görüntüsünü elde ederiz.
Şekil 1. System.Int32 sınıfının üyeleri.
Üye listesini incelediğimizde 15 üyenin olduğunu görürüz. Metodlar, alanlar vardır. Ayrıca dikkat ederseniz, Parse , ToString metodları birden fazla defa geçmektedir. Bunun nedeni bu metodların overload ( aşırı yüklenmiş ) versiyonlara sahip olmasıdır.
Kodları incelediğimizde, System.Int32 sınıfına ait tipleri GetMembers metodu ile, System.Reflection uzayında yer alan MemberInfo sınıfı tipinden bir diziye aldığımızı görürüz. İşte olayın önemli kodları bunlardan oluşmaktadır. MemberInfo dışında kullanabaileceğimiz başka Reflection sınıflarıda vardır. Bunlar;
| ConstructorInfo | Tipe ait yapıcı metod üyelerini ve bu üyelere ait bilgilerini içerir. |
| EventInfo | Tipe ait olayları ve bu olaylara ait bilgileri içerir. |
| MethodInfo | Tipe ait metodları ve bu metodlara ait bilgileri içerir. |
| FieldInfo | Tip içinde kullanılan alanları ve bu alanlara ilişkin bilgileri içerir. |
| ParameterInfo | Tip içinde kullanılan parametreleri ve bu parametrelere ait bilgileri içerir. |
| PropertyInfo | Tip içinde kullanılan özellikleri ve bu özelliklere ait bilgileri içerir. |
Tablo 1. Reflection Uzayının Diğer Kullanışlı Sınıfları
Şimdi bu sınıflara ait örneklerimizi inceleyelim.
Bu kez bir DataTable sınıfının üyelerini inceleyeceğiz. Örnek olarak, sadece olaylarını ve bu olaylara ilişkin özelliklerini elde etmeye çalışalım. Bu örneğimizde, yukarıda bahsettiğimiz tip-i-tip tekniğini biraz değiştireceğiz. Nitekim bu tekniği uygulamamız halinde bir hata mesajı alırız. Bunun önüne geçmek için, bir DataTable örneği (instance) oluşturup bu örneğin tipinden hareket edeceğiz. Dilerseniz hemen kodlarımıza geçelim.
| using System;
namespace ReflectionSample2 class Class1 Type tipimiz=dt.GetType(); /* DataTable örnegimizin GetType metodunu kullanarak, bu örnegin dolayisiyla DataTable sinifinin tipini elde ediyoruz. */ System.Reflection.MethodInfo[] tipMetodlari=tipimiz.GetMethods(); /* Bu kez sadece metodlari incelemek istedigimizden, GetMethods metodunu kullaniyor ve sonuçlari, MethodInfo sinifi tipinden bir diziye aktariyoruz.*/ Console.WriteLine(tipimiz.Name.ToString()+” sinifindaki metod sayisi:”+tipMetodlari.Length.ToString()); /* Metod sayisini Length özelligi ile aliyoruz.*/ /* Döngümüzü olusturuyor ve Metodlarimizi bir takim özellikleri ile birlikte yazdiriyoruz.*/ System.Reflection.ParameterInfo[] prmInfo=tipMetodlari[i].GetParameters(); Console.WriteLine(“—–Parametre Bilgileri—–“+prmInfo.Length.ToString()+” parametre”); for(int j=0;j<PRMINFO.LENGTH;++J) Console.WriteLine(“—-“); |
Şimdi uygulamamızı çalıştıralım ve sonuçlarına bakalım.
Şekil 2. System.Data.DataTable tipinin metodları ve metod parametrelerine ait bilgiler.
Reflection teknikleri yardımıyla çalıştırdığımız programa ait sınıflarında bilgilerini elde edebiliriz. İzleyen örneğimizde, yazdığımız bir sınıfa ait üye bilgilerine bakacağız.
Üyelerine bakacağımız sınıfın kodları;
| using System;
namespace ReflectionSample3 public int Deger public string metod(string a) int yas=27; } |
ikinci sınıfımızın kodları;
| using System; using System.Reflection; namespace ReflectionSample3 MemberInfo[] tipUyeleri=tipimiz.GetMembers(); for(int i=0;i<TIPUYELERI.LENGTH;++I) |
Şimdi uygulamamızı çalıştıralım.
Şekil 3. Kendi yazdığımı sınıf üyelerinede bakabiliriz.
Peki kendi sınıfımıza ait bilgileri edinmenin bize ne gibi bir faydası olabilir. İşte şimdi tam dişimize gore bir örnek yazacağız. Örneğimizde, bir tablodaki verileri bir sınıf içersinden tanımladığımız özelliklere alacağız. Bu uygulamamız sayesinde sadece tek satırlık bir kod ile, herhangibir kontrolü veriler ile doldurabileceğiz. Bu uygulamada esas olarak, veriler veritabanındaki tablodan alınıcak ve oluşturduğumuz bir koleksiyon sınıfından bir diziye aktarılacak. Oluşturulan bu koleksiyon dizisi, bir DataGrid kontrolü ile ilişkilendirilecek. Teknik olarak kodumuzda, Reflection uzayının PropertyInfo sınıfını kullanarak, oluşturduğumuz sınıfa ait özellikler ile tablodaki alanları karşılaştıracak ve uygun iseler bu özelliklere tabloda karşılık gelen alanlar içindeki değerleri aktaracağız. Dilerseniz kodumuz yazmaya başlayalım.
| using System; using System.Reflection; using System.Data; using System.Data.SqlClient; namespace ReflectDoldur private string kitapAdi; /* Özelliklerimizin adlarinin tablmuzdan alacagimiz alan adlari ile ayni olmasina dikkat edelim.*/ public string BasimEvi /* Yapici metodumuz parametre olarak geçirilen bir DataRow degiskenine sahip. Bu degisken ile o anki satiri aliyoruz.*/ /* Döngümüz ile tüm özellikleri geziyoruz. Eger metodumuza parametre olarak geçirilen dataRow degiskenimiz, bu özelligin adinda bir alan içeriyorsa, bu özellige ait SetValue metodunu kullanarak özelligimize, iligili tablo alaninin degerini aktariyoruz.*/ for(int i=0;i<PROPINFOS.LENGTH;++I) } /* KitapKoleksiyonu sinifimiz bir koleksiyon olucak ve tablomuzdan alacagimiz iki alana ait verileri Kitap isimli nesnelerde saklanmasini sagliyacak. Bu nedenle, bir CollectionBase sinifindan türetildi. Böylece sinifimiz içinde indeksleyiciler kullanabilecegiz.*/ public class KitapKoleksiyonu:System.Collections.CollectionBase public virtual void Add(Kitap _kitap) |
Ve işte formumuzda kullandığımız tek satırlık kod;
| private void btnDoldur_Click(object sender, System.EventArgs e) { dataGrid1.DataSource = new ReflectDoldur.KitapKoleksiyonu(); } |
Şimdi uygulamamızı çalıştıralım ve bakalım.
Şekil 4. Programın Çalışmasının Sonucu
Görüldüğü gibi tablomuzdaki iki Alana ait veriler yazdığımız KitapKoleksiyonu sınıfı yardımıyla, her biri Kitap tipinde bir nesne alan koleksyionumuza eklenmiş ve bu sonuçlarda dataGrid kontrolümüze bağlanmıştır. Siz bu örneği dahada iyi bir şekilde geliştirebilirisiniz. Umuyorumki bu örnekte yapmak istediğimizi anlamışsınızdır. Yansıma tekniğini bu kod içinde kısa bir yerde kullandık. Sınıfın özelliklerinin isminin, tablodaki alanların ismi ile aynı olup olmadığını ve aynı iseler yazılabilir olup olmadıklarını öğrenmekte kullandık.
Değerli Okurlarım. Geldik bir makalemizin daha sonuna. Hepinize mutlu günler dilerim.
