Öncelikle CollectionBase sınıfının yapısını biraz inceleyelim;
CollectionBase sınıfı soyut (abstract) bir sınıftır. Dolayısıyla bu sınıfın
bir örneğini oluşturup kullanmamız mümkün değil. Kendi koleksiyonumuzu oluşturmak
için ilk yapmamız gereken şey, yeni bir sınıf tanımlamak ve bu sınıfı
CollectionBase sınıfından türetmek.
CollectionBase, koleksiyona öğe eklemek, çıkarmak ve belirtilen bir
nesnenin koleksiyonda bulunup bulunmadığını öğrenebilmek için bir takım
metodlar içerir. Birazdan teker teker uygulayacağımız bu metodların tümü IList
arayüzüne ait metodlardır. CollectionBase sınıfından türettiğimiz koleksiyon sınıflarında,
saydığımız işlemleri gerçekleştirebilmek için, CollectionBase’in List özelliğinden
faydalanılır. List özelliği sayesinde yeni bir koleksiyon oluşturmak gerçekten
çok kolaydır.
Örneğimizde, içerisinde sadece Kitap sınıfından oluşturulmuş kitap
nesnelerinin saklanmasına izin veren yeni bir koleksiyon oluşturacağız. Daha
sonra bu koleksiyona farklı şekilde kitap nesneleri ekleyen, kitap ismine göre
koleksiyon içerisinde tarama yapan, standart koleksiyonlarda bulunmayan yeni
metodlar tanımlayacağız.
Koleksiyon sınıfımızı oluşturmadan önce, koleksiyon içerisinde saklayacağımız
Kitap nesnelerin tanımını yapalım.
using System;
namespace Koleksiyonlar {
/// <summary>
/// KitapKoleksiyonunu test etmek için
/// tanımladığımız özel sınıf.
/// </summary>
public class Kitap {
public Kitap() {}
public Kitap(string KitapAdi, string Yazar, DateTime BasimTarihi) {
this.KitapAdi = KitapAdi;
this.Yazar = Yazar;
this.BasimTarihi = BasimTarihi;
}
public string KitapAdi;
public string Yazar;
public DateTime BasimTarihi;
}
}
Koleksiyon içerisinde saklanacak Kitap nesnelerinin tanımı
Oluşturacağımız KitapKoleksiyonu adındaki koleksiyon, içerisinde sadece
yukarıda tanımladığımızKitap sınıfından oluşturulmuş nesnelerin saklanmasına
izin verecek. Farklı bir veri tipinde nesne eklenmek istenirse bir hata
(exception) fırlatılacak. Şimdi adım adım koleksiyonumuzu oluşturalım; İlk
yapmamız gereken, bir sınıf tanımlamak ve bu sınıfıCollectionBase’den türetmek:
using System;
using System.Collections;
namespace Koleksiyonlar {
public class KitapKoleksiyonu : CollectionBase {
public KitapKoleksiyonu() {}
}
}
KitapKoleksiyonu sınıfının tanımı
Sınıf tanımını yaptıktan sonra, koleksiyona işlerlik kazandırmak için
IList arayüzü içerisinde tanımlanan veCollectionBase’in List özelliği ile bize
sunulan metodları uygulamaya başlayabiliriz. Uygulayacağımız ilk metod bir
koleksiyona öğe eklenmesini sağlayan IList.Add metodu:
public int Add(Kitap value) {
return (List.Add(value));
}
KitapKoleksiyonu.Add
Koleksiyona öğe eklemek için gerekli olanAdd metodunun tanımını yaptık.
Metodun ne kadar kısa olduğunu farketmişsinizdir. Belirtilen öğenin listeye
eklenmesi için CollectionBase tarafından bize devredilenList özelliğinin Add
metodunu kullanmamız yeterli. List özelliği öğenin saklanması işini bizim için
hallediyor. Burada dikkat edilmesi gereken nokta, Add metodunun parametresinde
eklenecek olan öğenin veri tipini ArrayList ve diğer koleksiyonlarda olduğu
gibi object olarak tanımlamamış olmamız. Bizim yaptığımız tanımda value
parametresi Kitap veri tipinde. Böylece daha en baştan, koleksiyona veri tipi
Kitap olmayan nesnelerin eklenmesini engellemiş oluyoruz. Uygulayacağımız bir
sonraki metod IList arayüzününContains metodu:
public bool Contains(Kitap
value) {
return (List.Contains(value));
}
KitapKoleksiyonu.Contains
Contains metodu value parametresinde belirtilen bir kitap nesnesinin
koleksiyon içinde bulunup bulunmadığını bildiriyor. Anlaşıldığı gibi, eğer
parametrede belirtilen kitap nesnesi eğer daha önce Add metodu ile koleksiyona
eklenmişse metod True döndürüyor. Burada da List özelliğinden faydalandık.
CollectionBase.List gerekli olan işlemleri bizim için yine hallediyor. Bir
sonraki metod IList.IndexOf metodu:
public int IndexOf(Kitap
value) {
return (List.IndexOf(value));
}
KitapKoleksiyonu.IndexOf
ArrayList üzerinde sıkça kullandığımız bu metod, parametrede geçilen
nesnenin koleksiyon içerisindeki sırasını (indeksini), eğer belirtilen nesne
koleksiyonda yoksa “-1” döndürüyor.
public void Insert(int index, Kitap
value) {
List.Insert(index, value);
}
KitapKoleksiyonu.Insert
Koleksiyonumuzun Insert metodu, koleksiyon içerisine istediğimiz bir
pozisyona bir kitap nesnesi eklememizi sağlıyor.
public void Remove(Kitap
value) {
List.Remove(value);
}
KitapKoleksiyonu.Remove
Remove metodu belirtilen bir kitap nesnesinin koleksiyondan atılmasını
gerçekleştiriyor.
Koleksiyonda sakladığımız Kitap nesnelerine indeks numarası belirterek
ulaşabilmek için koleksiyonumuzda indeksleyiciler tanımlamamız gerekiyor:
public Kitap this[int index] {
get {
return ((Kitap) List[index]);
}
set {
List[index] = value;
}
}
KitapKoleksiyonu indeksleyici tanımı
Yukarıdaki indeksleyici tanımı sayesinde, indeks belirtilerek koleksiyon
içerisinde saklanan kitap nesnelerine ulaşmak mümkün hale geliyor. Yaptığımız
tek şey List içerisinden belirtilen indekse sahip nesneyi çekmek, onu Kitap
nesnesine dönüştürmek ve geri döndürmek. Belirtilen indeksin limitler
içerisinde olup olmadığını kontrol etmemize ayrıca gerek yok; çünkü List, bu
kontrolü zaten gerçekleştiriyor ve eğer belirtilen indeks koleksiyon içerisindeki
nesne sayısından fazla ise bir hata (exception) fırlatılıyor.
Buraya kadar yaptığımız herşey standart bir koleksiyon içerisinde olan
metodları tanımlamaktan ibaretti. Bu metodları oluştururken sürekli olarak List
özelliğinden faydalandık. List, arka planda yapılması gereken herşeyi bizim
için gerçekleştirdi. ArrayList’ten farklı olarak bizim koleksiyonumuz,
listesine, sadece Kitap sınıfından oluşturulmuş nesnelerin eklenmesine izin
veriyor. Bunu da Add, Insert,Remove metodlarında parametreleri Kitap veri
tipinde tanımlayarak gerçekleştirdik.
Madem koleksiyonumuz sadece Kitap nesnelerini saklayacak, öyleyse Add,
Contains, Insert metodlarının isteğimize göre özelleştirdiğimiz versiyonlarını
tanımlayabiliriz. Ayrıca kitap adına göre indeksleme yapabilir, IndexOf
metodunu kitap ismine göre indeks numarası döndürecek hale getirebiliriz. Add
metodundan başlayalım:
public int Add(string KitapAdi, string Yazar, DateTime BasimTarihi) {
return (List.Add(new Kitap(KitapAdi, Yazar, BasimTarihi)));
}
KitapKoleksiyonu.Add
Add metodunun aşırı yüklenmiş (! overloaded) versiyonu, Kitap sınıfının
tanımına uygun parametreler alıyor, yeni bir kitap nesnesi oluşturuyor ve oluşturduğu
kitap nesnesini koleksiyona ekliyor. BöyleceAdd metodunun iki versiyonunu yazmış
olduk. Birincisi listeye eklemek için parametre olarak bir kitap nesnesi kabul
ediyor, diğeri iseKitapAdi, Yazar ve BasimTarihi parametrelerini kullanarak
kitap nesnesini kendisi oluşturup listeye ekliyor. Aynı işlemi Insert metodunda
da kullanabiliriz:
public void Insert(int index, string KitapAdi, string Yazar, DateTime
BasimTarihi) {
List.Insert(index, new Kitap(KitapAdi, Yazar, BasimTarihi));
}
KitapKoleksiyonu.Insert
Insert metodu da Add ile aynı şekilde, aldığı parametrelere göre yeni
bir kitap nesnesi oluşturuyor ve koleksiyona ekliyor. Contains, IndexOf ve
Remove metodlarını kitap adına göre çalışan indeksleyicimizi yazdıktan sonra
uygulayacağız. Önce indeksleyicimizi tanımlayalım:
public Kitap this[string kitapAdi] {
get {
foreach (Kitap kitap
in List) {
if (kitap.KitapAdi == kitapAdi)
return kitap;
}
return ((Kitap) null);
}
set {
Kitap kitap = this[kitapAdi];
if (kitap != null)
List[IndexOf(kitap)] = value;
}
}
Kitap adına göre çalışan indeksleyici
Indeksleyicimiz kitap adına göre çalıştığındanget metodu koleksiyon
içerisinde foreach ile bir tarama gerçekleştiriyor. Eğer koleksiyon içerisinde
belirtilen isimde bir kitap bulursa, bulduğu kitap nesnesini döndürüyor. Eğer
kitapAdi parametresi ile geçilen isimde bir kitap bulunamazsa, indeksleyici
null döndürüyor. Bu arada şunu da eklemekte fayda var; Koleksiyon içerisinde eğer
aynı isimde birkaç kitap varsa, indeksleyici sadece ilk rastladığı kitabı
döndürüyor.
Indeksleyicinin set metodu,get metodundan faydalanıyor. Set metodu önce
kitapAdı parametresindeki isme sahip kitabı kapalı bir şekilde get erişim
metodu ile çekiyor. Çekilen kitap nesnesi null değilse, arka plandaki List
nesnesine ulaşarak, get ile bulunan kitabı value parametresi ile gelen kitapla
değiştiriyor. İndeksleyiciyi oluşturduğumuza göre Contains, IndexOf ve Remove
metodlarını indeksleyiciyi kullanarak uygulayabiliriz. ÖnceContains metodu:
public bool Contains(string KitapAdi) {
return (this[KitapAdi] != null);
}
KitapKoleksiyonu.Contains
Contains metodu isme göre çalışan indeksleyiciden faydalanıyor.
Indeksleyiciyi kullanarak, belirtilen isimde bir kitap bulunamaz ise false
döndürüyor.
public int IndexOf(string KitapAdi) {
return (List.IndexOf(
this[KitapAdi]));
}
KitapKoleksiyonu.IndexOf
IndexOf metodu da indeksleyiciyi kullanarak, önce belirtilen isme göre
kitaba ulaşıyor, daha sonra List üzerindeIndexOf metodunu çağırarak kitabın
indeksini döndürüyor.
public void Remove(string kitapAdi) {
List.Remove(this[kitapAdi]);
}
KitapKoleksiyonu.Remove
Remove metodu yine indeksleyici üzerinde belirtilen isimdeki kitabı
buluyor ve List.Remove metodu ile kitabı koleksiyondan siliyor.KitapKoleksiyonu
üzerinde böylece tüm işlemleri tamamlamış olduk. Koleksiyonumuz artık sadece
Kitap nesneleri ile çalışan, ve hatta kitap ekleme ve silme işlemlerini sadece
indeks numaraları üzerinden değil, kitap isimlerine göre de yapabilen bir
koleksiyon haline geldi. Koleksiyonumuza Kitap nesneleri dışında hiçbir
nesnenin eklenemeyeceğini söylemiştik, bir istisna dışında;Kitap sınıfından
türetilmiş sınıfların örnekleri koleksiyona eklenebilir. Örneğin:
public class YemekKitabi : Kitap {
}
Kitap sınıfından türetilmiş YemekKitabi sinifi
şeklinde tanımını yaptığımız yeni sınıftan oluşturulan nesneler koleksiyona
eklenebilir. Eğer bunu da engellemek istiyorsakCollectionBase’in OnInsert ve
OnSet metodlarının üzerine yazmamız gerekir. Bu iki metod koleksiyona bir nesne
eklendiğinde ve indeksleyici kullanılarak koleksiyondaki bir nesne bir başkası
ile değiştirildiğinde çağırılır. Bu iki metodun üzerinde yazarak, koleksiyona
eklenen nesnenin veri tipini kontrol edebiliriz:
protected override void OnInsert(int index, object value) {
if (value.GetType() != Type.GetType("Koleksiyonlar.Kitap"))
throw new ArgumentException("Listeye Kitap sınıfından oluşturulmuş
nesneler eklenebilir.", value");
}
KitapKoleksiyonu.OnInsert
OnInsert metodu içerisinde listeye eklenmek istenen nesnenin veri tipini
kontrol ediyoruz. Eğer veri tipiKoleksiyonlar.Kitap veri tipinden farklı ise
bir ArgumentException fırlatıyoruz. BöyleceInsert metodunun çağırılmasının
önüne geçmiş ve nesnenin koleksiyona eklenmesini engellemiş oluyoruz. Aynı işlemi
OnSet metodu için tekrar edeceğiz:
protected override void OnSet(int index, object oldValue, object
newValue) {
if (newValue.GetType() != Type.GetType("Koleksiyonlar.Kitap"))
throw new ArgumentException("Listeye Kitap sınıfından oluşturulmuş
nesneler eklenebilir.", “newValue");
}
KitapKoleksiyonu.OnSet
Böylece koleksiyona Kitap nesnelerinden başka nesnelerin eklenmesini
imkansız hale getirmiş olduk. Koleksiyonumuz kullanılmaya hazır...Kodları
toparlarsak;
KitapKoleksiyonu.cs
using System;
using System.Collections;
namespace Koleksiyonlar {
public class KitapKoleksiyonu : CollectionBase {
public Kitap this[int index] {
get {
return ((Kitap) List[index]);
}
set {
List[index] = value;
}
}
public Kitap this[string kitapAdi] {
get {
foreach (Kitap kitap
in List) {
if (kitap.KitapAdi == kitapAdi)
return kitap;
}
return ((Kitap) null);
}
set {
Kitap kitap = this[kitapAdi];
if (kitap != null)
List[IndexOf(kitap)] = value;
}
}
public int Add(Kitap value) {
return (List.Add(value));
}
public int Add(string KitapAdi, string Yazar, DateTime BasimTarihi) {
return (List.Add(new Kitap(KitapAdi, Yazar, BasimTarihi)));
}
public bool Contains(Kitap value) {
return (List.Contains(value));
}
public bool Contains(string KitapAdi) {
return (this[KitapAdi] != null);
}
public int IndexOf(Kitap value) {
return (List.IndexOf(value));
}
public int IndexOf(string KitapAdi) {
return (List.IndexOf(this[KitapAdi]));
}
public void Insert(int index, Kitap value) {
List.Insert(index, value);
}
public void Insert(int index, string KitapAdi, string Yazar, DateTime
BasimTarihi) {
List.Insert(index, new Kitap(KitapAdi, Yazar, BasimTarihi));
}
public void Remove(Kitap value) {
List.Remove(value);
}
public void Remove(string kitapAdi) {
List.Remove(this[kitapAdi]);
}
protected override void OnInsert(int index, object value) {
if (value.GetType() != Type.GetType("Koleksiyonlar.Kitap"))
throw new ArgumentException("Listeye sadece Kitap nesneleri
eklenebilir.", "value");
}
protected override void OnSet(int index, object oldValue, object
newValue) {
if (newValue.GetType() != Type.GetType("Koleksiyonlar.Kitap"))
throw new ArgumentException("Listeye sadece Kitap nesneleri
eklenebilir.", "newValue");
}
}
}
Kitap.cs
using System;
namespace Koleksiyonlar {
public class Kitap {
public Kitap() {}
public string KitapAdi;
public string Yazar;
public DateTime BasimTarihi;
public Kitap(string KitapAdi, string Yazar, DateTime BasimTarihi) {
this.KitapAdi = KitapAdi;
this.Yazar = Yazar;
this.BasimTarihi = BasimTarihi;
}
}
}
KoleksiyonTest.cs
using System;
namespace Koleksiyonlar {
public class KoleksiyonTest {
public KoleksiyonTest() {}
[STAThread]
public static void Main() {
// Tanımladığımız koleksiyondan bir nesne oluşturuyoruz...
KitapKoleksiyonu koleksiyon = new KitapKoleksiyonu();
// Koleksiyona kitap nesneleri ekliyoruz...
Kitap kitap1 = new Kitap("Kitap 1", "Yazar 1", new
DateTime(1970, 1, 1));
koleksiyon.Add(kitap1);
koleksiyon.Add("Kitap 2", "Yazar 2", DateTime.Now);
Console.WriteLine("Koleksiyondaki kitaplar:");
foreach (Kitap kitap
in koleksiyon) {
Console.WriteLine("Kitap Adı:{0}\nYazar:{1}", kitap.KitapAdi,
kitap.Yazar);
}
// Indeksleyici kullanarak kitap nesnesine ulaşıyoruz...
Console.WriteLine("Indeksleyici ile erişim.");
Console.WriteLine(koleksiyon[0].KitapAdi);
// Kitaba indeksleyici ile kitabın ismini kullanarak ulaşıyoruz...
Console.WriteLine(koleksiyon["Kitap 2"].Yazar);
// Kitaplardan birini siliyoruz...
koleksiyon.Remove("Kitap 2");
Console.WriteLine(koleksiyon.Count);
}
}
}
Hiç yorum yok:
Yorum Gönder