Her ne kadar ArrayList, Stack veQueue
gibi sınıflar nesne koleksiyonlarını saklamak için çoğu zaman ihtiyaçlarımıza
karşılık verseler de bazı durumlarda, sadece belli veri tiplerinin saklanmasına
izin veren koleksiyonlara ihtiyacımız olabilir. Bu gibi durumlardaArrayList
sınıfı ile aynı isim uzayı içerisinde bulunan CollectionBase sınıfından
faydalanarak işimizi oldukça kolaylaştırabiliriz.
Ö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);
}
}
}
|
Önsel Akın
MCSD.Net, MCSE, MCDBA, CCNA
[email protected]
Makale:
Tiplendirilmiş Koleksiyonlar Oluşturmak C#, Visual C# ve .NET Önsel Akın
|