C# IDictionary Interface

Merhaba arkadaşlar,

Collections nesnelerini daha iyi anlamak için System.Collection isim alanında bulunan arayüzleri tanımaya devam ediyoruz. Bir önceki yazımda IComparer arayüzünü incelemiştik. (IComparer yazıma buradan ulaşabilirsiniz)

Programlama yaparken grup nesnelerimize farklı yollardan erişmek isteyebiliriz. Array sınıfında her bir elemanına indeks yardımı ile eriştiğimizi hatırlarsınız. Erişebilmek için for yapısı ile dizinin boyutu kadar dönerdik. Bazı durumlarda grup nesnelerimize indeks ile değil de anahtar-değer ikilisi ile erişmek isteyebiliriz. .Net kütüphanesinde bunun için özelleştirilmiş ve genişletilmiş sınıflar var ama biz işin mantığını öğrenmek ve örnek üzerinden pekiştirmek için IDictionary arayüzünü uygulayan kendi sınıfımızı inşa edeceğiz.

IDictionary ne işe yarıyor? Bu arayüzü anahtar-değer ikilisi gibi çalışan koleksiyon sınıfları uygular. Bu arayüz ICollection arayüzünden türetilmiştir o yüzden ICollecion metot ve özellikleri de uygulanır. Bu arayüzün özelliklerinde göze çarpan Count, Keys, Values ve Item var.

  • Count özelliği, koleksiyon içindeki eleman sayısını döner.
  • Keys özelliği, koleksiyon nesnemizdeki anahataları ICollection türünden verir
  • Values özelliği, koleksiyon nesnesindeki değerleri ICollection türünden verir
  • Item özelliği, aslında bir indeksleyici (indexer) belirtilen anahtara sahip değeri verir veya değeri günceller.

IDictionary arayüzüne buradan daha detaylı bilgiye ulaşabilirsiniz.

Hadi şimdi kendi anahtar-değer ikilisine sahip sınıfımızı geliştirelim. Bunun için MyDictionary sınıfı oluşturup IDictionary arayüzünü uyguluyoruz.

Gördüğünüz üzere IDictionary arayüzünü uyguladığımızda bazı özellik ve metotların kendi sınıfımıza eklendiğini gördük. Aslında bunlar sayesinde kendi sınıfımıza anahtar-değer özelliğini kazandırmış olduk. Bu aşamada bizim anahtar değer ikilisini tutabilecek, güncelleyebilecek ve ekleyebilecek bir grup nesnesine ihtiyacız var. Bu nesne farklı veri türlerinide barındırabilecek. Bunu .Net Kütüphanesinde bulunan DictionaryEntry sınıfı ile yapacağız. DictionaryEntry anahtar-değer ilişkisini tutabilen ve yönetebilen bir koleksiyon tabanlı nesnedir. O zaman DictionaryEntry türünde bir dizi özelliği ekliyoruz ve yapıcı metotla bu sınıftan bir nesne oluşturuyoruz.

Yavaş, yavaş diğer metotların içini doldurmaya başlayalım. Dizimize eklemek için Add metoduna ihtiyacımız var. Add metodunun uygulanmasına başlayalım. Eğer kullandığım index oluşturduğumuz diziye eşitse hata fırlatmalı ki o değeri eklemeyelim. index özellğini kullanaray dizimize DictionaryEntry türünde eleman ekliyoruz.

Eleman ekledik. Peki elemanları silmek istersek. Clear metodunun uygulanmasına başlayalım. Dizi içine eklediğimiz tüm elemanları sil ve indexi başlangıç noktasına getirmeliyiz. Dizi içindeki her bir elemanı default değerine getirmeliyiz

Elemanları diziden temizledik. Şimdi istediğimiz eleman dizide var mı yok mu kontrolü için Contains metodunu uygulayacağız.

Anahtar parametresi ile gelip dizide ilgili anahtar var mı yok mu kontrolü için dizinin her bir elemanı kontrol edip o anahtar ile eşleşen bir değer var mı kontrolü yapıyoruz. Eğer eşleşen var ise true yok ise false değerini döndürüyoruz.

Anahtarın dizide olup olamadığını kontrol ettik peki var olan anahtarı koleksiyon nesnemizden silmek istersek Remove metodunu kullanmalıyız. Şimdi Remove metodunu uygulayalım

Remove metodunda dikkatinizi çeken Array.Copy() metodu ile yaptığımız işlem olmuştur. Burada anahtarı bulduğumuz indeksten sonraki elemanları anahtarı bulduğumuzdan indeksten başlayıp elemanları kopyalıyoruz yani sola doğru kaydırıyoruz.

Yukarıdaki örnekte index 2 deki 3 elamanı diziden siliniyor. 3 elemanından sonra gelen 4 ve 5 elemanı dizideki eleman sayısı – indeks -1 ile hesaplanıp silinen 3 elemanın indeksinden başlayıp kopyalanıyor. Kopyalama 4 ve 5 eleman için yapılıyor.

IDictionary bir diğer özelliği olan Count özelliğini uygulayalım. Count ile dizideki eleman sayısını döneceğiz.

Eleman sayısını uyguladık. Şimdi ise anahtar-değer tabanlı koleksiyon sınıfımızdan sadece anahtarları dönen Keys özelliğini uygulayalım. Ben ICollection dönen private GetKeys() metodu tanımladım. Aslında Keys özelliğini kapsülledim. Siz isterseniz Keys özelliğinin get kapsamına yazabilirsiniz.

Keys özelliğini uyguladıktan sonra bu özelliği anlamlı kılacak olan Values özelliğini uygulayalım. Values özelliği Keys özelliğine çok banzer aradaki far nesne üzerinden key yerine value eklenmesi.

Neredeyse sınıfımız hazır gibi. Koleksiyon tabanlı sınıfımızın elemanları arasında ilerlemek ve işlem yapmak için IEnumerator ve IDictionaryEnumerator arayüzlerini uygulayacağız. IEnumerator kısaca değinecek olursak; koleksiyondaki elemanlara erişebilmemiz için uygulamamız gereken arayüz. (IEnumerator yazıma buradan ulaşabilirsiniz) IDictionaryEnumerator ise IEnumerator ile aynı mantığa sahip. Bu sayede koleksiyon içindeki elemanlara anahtar-değer ikilisi ile erişebileceğiz.

IDictionaryEnumerator arayüzü, anahtar-değer iki çiftlerden sadece anahtar, sadece değer ya da hem anahtar hem değer çiftlerini elde etmek için Value, Key ve Entry isimli 3 tane özellik bulunur. Bu Enumerator sayesinde koleksiyon sınıfımızdaki her bir elemanın anahtar ve değer çiftine erişebilmemizi sağlayacak.

IDictionaryEnumerator arayüzü buradan detaylı bilgiye ulaşabilirsiniz.

Daha önceden IEnumerator yazımda bu arayüzün nasıl uygulandığını görmüştük. IDictionaryEnumerator arayüzü de aynı mantıkla uygulanacağı için burada detayına girmeyeceğiz.

Koleksiyon sınıfımızı kullanarak bir döngü içinde kullandığımızda foreach yapısı gibi devreye iterasyon girip GetEnumearator() metodu çalışır. IDictionary arayüzünde IDictionaryEnumerator türünde dönen GetEnumerator() metodu olduğunu fark etmişsinizdir. Tadınıdık geldi mi? IEnumerable arayüzünde de GetEnumerator() metodu vardı. IDictionary aynı zamanda IEnumerable arayüzünü de uyguladığı için kendi koleksiyon tabanlı sınıfımıza implicit ve explicit olarak uygulanmıştır. (implicit ve explicit hatırlamak için interface yazıma bakabilirsiniz )

O halde ihtiyacımız olan Enumerator’ü geliştirmeye başlayalım. MyDictionaryEnumerator sınıfı oluşturuyoruz ve IDictionaryEnumerator arayüzünü uyguluyoruz. IDictionaryEnumerator arayüz için uygulamamız gereken özellik ve metotlar karşımıza çıkıyor.

Arayüzün kendi sınıfımıza kazandırdığı özelliklere ve metotlara bakacak olursak anahtar-değer ikilisi için gereken bir iterasyon olduğunu anlayabiliriz.

  • Entry geriye bir DictionaryEntry türünde nesne verir ve bu nesne sayesinde anahtar-değer ikilisine erişebiliriz.
  • Key özelliği anahtar değerini, Value özelliği ise değer değerini verir.
  • Current özelliği ise IEnumerator arayüzünden uygulanmıştır. Buda foreach yapısında ilgili elemana erişmemiz için gereken özellik.
  • Reset() metodu ise Enumerator nesnemizi ilk konumuna dönmesini sağlayan metottur.
  • MoveNext() metodu ile koleksiyondaki bir sonraki elemana ilerletiyoruz

Şimdi sınıfımızın içini bu bilgilere göre uygulamaya çalışalım. İhtiyacımız olan DictionaryEntry türünde bir özellik. Kendi geliştirdiğimiz koleksiyon tabanlı sınıfımızdaki elemanları bu Enumerator aktarmamız gerekiyor. Şimdi DictionaryEntry türünde bir dizi özelliği ekliyoruz ve yapıcı metoduna kendi sınıfımızı referans olarak veriyoruz.

Yapıcı metot ile sınıfımızdaki elemanları alıyoruz. index özelliği ise koleksiyon içindeki elemanlara erişebilmemiz için gereken özellik.

foreach yapısını ele aldığımızda ilk çalışacak olan MoveNext() metodu. Bu metot sayesinde koleksiyon içindeki elemanları ilerleyebileceğiz.

MoveNext() metodu eğer koleksiyonun içindeki eleman sayısı aşılmadıysa geriye true değerini dönecek ve döngü hayarına devam edebilecek. false değeri dönmesi durumunda döngü sona erecek.

MoveNext() metodu çalıştıktan sonra koşulu sağlıyorsa Current Özelliği devreye girecek. Current özelliğini uygulayalım.

Iterasyonda Key ve Value özelliğinden yararlanmak için onları da uygulamamız gerekiyor.

Son kalan özelliğimiz olan Entry uygulayalım. Entry DictionaryEntry türünde olan bir özelliktir. foreach yapılarında değil de direkt IDictionaryEnumerator üzerinden elemanlara cast işlemi yapmadan erişmek için bu özelliği kullanırız.

IDictionaryEnumerator arayüzünü kendi Enumerator sınıfa uyguladık. Enumerator tabanlı sınıfımızın son hali

Kendi Enumerator sınıfımız uyguladık ve bu sınıfı koleksiyon tabanlı sınıfımıza bildirimemiz gerekiyor. Yani MyDictionary sınıfımızdaki GetEnumerator() metoduna MyDictionaryEnumerator sınıfını bildiriyoruz.

IDictionary özelliği kazandırdığımız kendi sınıfımızı artık kullanabilir hale getirdik. Şimdi kendi geliştirdiğimiz koleksiyon tabanlı anahtar-değer ikilisine dayalı sınıfımızı kullanarak örnek yapabiliriz.

Kodun son hali:

Bu yazımızda klasik tipli koleksiyonlarda IDictionary arayüzünün işlevini ve nasıl uygulanması gerektiğini görmüş olduk. Umarım faydalı olmuştur.

Bir sonraki yazımda System.Collection isim alanında bulunan IList arayüzünden bahsedip örnek bir uygulama ile pekiştiriyor olacağız.

Kaynaklar:

Her Yönüyle C# 7.0, Sefer Algan, Pusula Yayincilik

https://docs.microsoft.com/tr-tr/dotnet/api/system.collections.idictionary?view=netframework-4.8

https://docs.microsoft.com/tr-tr/dotnet/csharp/programming-guide/concepts/collections

Leave a Comment