COLLECTION BASE SINIFI ILE KENDI KOLEKSIYONLARIMIZI YAZMAK
Bu makalemizde CollectionBase sınıfından yararlanarak kendi koleksiyonumuzu yazıyor olacağız. Öncelikle koleksiyonların ne olduğunu hatırlayalım. Koleksiyonları ilk etapta bir dizi gibi düşünebiliriz. Diziler aynı tipten veya farklı tiplerden birçok değeri taşımak için kullandığımız referans tipli yapılardır.Örnek olarak 5 gözlü bir integer dizisi için tanımlama aşağıdaki gibi oluyordu :
int[] sayilar = new int[5];
Bu şekilde tanımladığınız bir dizi ile 5 adet integer bilgiyi taşıyabiliriz. Böyle bir yapıda canımızı sıkan iki nokta var :
- Tüm değerlerin integer olması gerektiği, başka bir bilgi taşıyamıyor olmamız
- 5 sayıdan fazla taşımak istersek Array.Resize metotunu kullanmak zorunda kalmamız (ki kendisi C# a 2.0 ile birlikte eklenmiştir J)
Bu iki problemin birincisinden object dizisi kullanarak kolayca kurtulabiliyoruz. Fakat bununda yanında getirdiği bazı problemler var. Bu problemler den biri bu koleksiyonun içerisine object olduğu için herşeyi ekleyebiliyor olmamız.
İkinci problemden ise ArrayList veya benzeri bir koleksiyon kullanarak kurtulabiliyoruz.
ArrayList koleksiyonunda da biraz önce bahsettiğimiz problem yine geçerli. Koleksiyonları hem resize işlemlerinden kurtulmak için hemde object türünden değerler taşıdıklarından istediğimiz tiple çalışmak için tercih ederiz.Fakat bir yazılım geliştirme ekibi içerisinde çalıştığınızı düşünürseniz ve siz sadece dll hazırlamak ile uğraşıyorsanız, tip güvenliğine önem vermeniz gerekecektir. Örneğin bir Ogrenci Takip programı yazarken öğrencilerin listesinin tutulduğu koleksiyonda bir DateTime değerin durması pek hoş olmayacaktır. Sebebi ise o koleksiyonu bir gridde veya dropdownlist içerisinde DataSource olarak kullanamayacak olmanız. Bu örnekler daha da çoğaltılabilir.
Framework 2.0 ile birlikte Generic tipler sayesinde çözülen bu problem 1.1 versiyonunda çalışırken CollectionBase vb sınıflar ile çözülüyordu. Bu makalemizde ki konumuz ise CollectionBase sınıfı ile bu işlemi nasıl çözüyor olduğumuz.
CollectionBase sınıfı bir taban sınıf olduğundan dolayı kendisini instance çıkartarak kullanamıyorsunuz. Aşağıda CollectionBase sınıfı ile ilgili bir metadata bilgisi yer almaktadır.
namespace System.Collections
{
[Serializable]
[ComVisible(true)]
public abstract class CollectionBase : IList, ICollection, IEnumerable
{
protected CollectionBase();
protected CollectionBase(int capacity);
[ComVisible(false)]
public int Capacity { get; set; }
public int Count { get; }
protected ArrayList InnerList { get; }
protected IList List { get; }
public void Clear();
public IEnumerator GetEnumerator();
protected virtual void OnClear();
protected virtual void OnClearComplete();
protected virtual void OnInsert(int index, object value);
protected virtual void OnInsertComplete(int index, object value);
protected virtual void OnRemove(int index, object value);
protected virtual void OnRemoveComplete(int index, object value);
protected virtual void OnSet(int index, object oldValue, object newValue);
protected virtual void OnSetComplete(int index, object oldValue, object newValue);
protected virtual void OnValidate(object value);
public void RemoveAt(int index);
}
}
Metadata gibi bilgilerle cok fazla mesgul olmadan asıl kodlarımıza geçiyoruz. Öncelikle Ogrenci sınıfımızı hazırlayalım.
public class Ogrenci
{
static int sayac = 0;
public Ogrenci()
{
this._siraNo = ++sayac;
}
int _siraNo;
public int SiraNo
{
get { return _siraNo; }
}
string _isim;
public string Isim
{
get { return _isim; }
set { _isim = value; }
}
string soyIsim;
public string SoyIsim
{
get { return soyIsim; }
set { soyIsim = value; }
}
public override string ToString()
{
return "Adı - Soyadı : " + this._isim + " " + this.soyIsim;
}
}
Class hakkında ufak bir açıklama yapmak gerekirse, öğrenci ile ilgili isim soyisim ve sira numarası gibi bilgilerimizi taşıyoruz. Fakat SıraNo değeri kullanıcı tarafından değil sistem tarafından veriliyor. Her instance oluşturulduğunda sınıftaki constructor sayesinde static ve private olan bir değişken bir arttırılıyor böylece sıra numarası sırayla birer birer arttırılıyor.
Şimdi gelelim koleksiyonumuzu oluşturmaya :
public class Sinif:CollectionBase
{
public void Ekle(Ogrenci ogr)
{
this.List.Add(ogr);
}
public void Ekle(Ogrenci ogr, int index)
{
this.List.Insert(index, ogr);
}
public void Sil(Ogrenci ogr)
{
if (this.List.Contains(ogr))
this.List.Remove(ogr);
}
public void Sil(int index)
{
if (this.List.Count > index)
this.List.RemoveAt(index);
}
public Ogrenci this[int index]
{
get { return (Ogrenci)this.List[index]; }
set { this.List[index] = value; }
}
}
CollectionBase sınıfından türeme işlemi yaptığınız zaman sınıfınıza miras yoluyla List adında bir koleksiyon gelmektedir.IList türünden olan bu koleksiyon object türünden değer taşır ve önemli olan bu üye sınıfınıza protected olarak geçmektedir. Yani List ismindeki üyemizden kimsenin haberi yok J
Koleksiyon sınıfımıza iki adet ekle metotu iki adet sil metotu ve bir adet indexer dediğimiz tüm koleksiyonlardan alışık olduğunuz :
ArrayList liste = new ArrayList();
liste.Add(?123?);
liste[0]=?Abc?;
şeklinde kullandığımız indeksleyici bulunmakta. Bunları hazırladıktan sonra artık bu uygulamamızı kullanacak olan bir windows application hazırlamaya başlayalım. Aşağıdaki gibi bir form tasarımı hazırladım :
En üstten en alta doğru sırasıyla TextBox isimlerimiz :
· txtAdi
· txtSoyadi
· txtSiraNo
· txtAramaAdi
· txtAramaSoyadi
Aşağıda ise Form1 içerisinde koleksiyonun kullanımının kodları bulunmakta, önce kodları inceleyelim sonra da kodlar üzerine konuşalım :
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace CollectionBaseMakale
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
void Doldur()
{
listBox1.Items.Clear();
foreach (Ogrenci ogr in liste)
{
listBox1.Items.Add(ogr);
}
}
Sinif liste = new Sinif();
private void btnEkle_Click(object sender, EventArgs e)
{
Ogrenci ogr = new Ogrenci();
ogr.Isim = txtAdi.Text;
ogr.SoyIsim = txtSoyadi.Text;
liste.Ekle(ogr);
this.Doldur();
}
private void btnBul_Click(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(txtSirano.Text))
{
int aranan = Convert.ToInt32(txtSirano.Text);
foreach (Ogrenci ogr in liste)
{
if (ogr.SiraNo == aranan)
{
txtAramaAdi.Text = ogr.Isim;
txtAramaSoyadi.Text = ogr.SoyIsim;
break;
}
}
}
else
MessageBox.Show("Arama işlemi için sıra numarası girmelisiniz!");
this.Doldur();
}
private void btnDegistir_Click(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(txtSirano.Text))
{
int aranan = Convert.ToInt32(txtSirano.Text);
foreach (Ogrenci ogr in liste)
{
if (ogr.SiraNo == aranan)
{
ogr.Isim = txtAramaAdi.Text;
ogr.SoyIsim = txtAramaSoyadi.Text;
break;
}
}
}
else
MessageBox.Show("Arama işlemi için sıra numarası girmelisiniz!");
this.Doldur();
}
private void btnSil_Click(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(txtSirano.Text))
{
int aranan = Convert.ToInt32(txtSirano.Text);
foreach (Ogrenci ogr in liste)
{
if (ogr.SiraNo == aranan)
{
liste.Sil(ogr);
MessageBox.Show("Silme işlemi tamamlandı!");
break;
}
}
}
this.Doldur();
}
}
}
Yukarıdaki kodlarımızı açıklamaya başlayalım. Öncelikle Doldur ismindeki metot en alttaki listbox kontrolünü her işlemden sonra doldurmakla görevli. Onun haricinde görüldüğü üzere Global olarak bir Sinif nesnesi tanımlanmış. Daha sonra ekle düğmesine basıldığı zaman bu koleksiyona yeni bir öğrenci nesnesi ekleniyor. Tabiki otomatik olarak bir sıra numarası alıyor. Bul diyince sıra numarasına göre arama yapılıp aranan öğrenci bulunuyor. Değiştirme ve silme işlemide aynı bu yöntemle çalışıyor.
Bizim için asıl önemli olan konu koleksiyonumuzun özel bir tiple çalışıyor olması. Hazırladığımız koleksiyon object tipinden veriler kabul ederek değil de Ogrenci sınıfı ile çalışıyor böylece hazırladığınız koleksiyonda başka bir tip kullanma şansınız kalmıyor.
Bu makalede CollectionBase isimli sınıfa değinmiş olduk. Bir başka makalede görüşmek üzere hepinize iyi çalışmalar.
Sorularınız için
bora.burgucugil@bilgeadam.com
adresine mail atabilirsiniz.