C
sharp ‘da her hangi bir koleksiyon tipinin elemanlarını teker teker bir döngüde
ele alabilir, istersek bu elemanlara değer atayabilir (set), istersek de bu
elemanları okuyabiliriz (get). Bu işlemler için en ideal döngü Foreach
döngüsüdür ki: kelime anlamı da her biri demektir. Biz de koleksiyon
içerisindeki her bir eleman için dön tabirini kullanacağız. For döngüsünden
farklı olarak her hangi bir iteration kullanmayız fakat arka planda kendisi bir
sonraki elemana geçer. Bu yüzden foreach ile yapılabilen her şey for döngüsü
ile de yapılabilir. Fakat for döngüsü ile yapılan her şey foreach döngüsü ile
yapılır dersek yalan söylemiş oluruz.
Söz
dizimine (syntax ‘ına) bakacak olursak, öncelikle koleksiyon içerisindeki her
bir elemanın tipi yazılır. Daha sonra ilgili koleksiyonun her bir elemanına,
foreach döngüsü içerisinde hangi isimle sesleneceğimiz belirten bir değişken
adı belirtilir. Daha sonra “in”
anahtar sözcüğü kullanılarak hangi koleksiyonun elemanlarında dönecek isek o
koleksiyonun adı yazılır. Aşağıda bir örnek bulunmaktadır.
foreach
(elemanTipi değiskenAdı in koleksiyonAdi)
{
}
Foreach
Döngüsü ile koleksiyon içerisindeki her bir elemanın değerini okuma :
Hemen bir örnek
üzerinde foreach döngüsü ile bir koleksiyon içerisindeki elemanları okumayı
inceleyelim. “Sehirler” adında string bir dizimiz olsun ve bu dizi elemanlarını
bir kontrolde teker teker gösterelim. Bir “Windows Form Application” açalım.
Formumuza bir adet ListBox kontrolü bırakalım. ListBox ‘ın ismini de
“lstOgreler” olarak değiştirelim. Kodlarımızı formun Load event ‘ine yazalım.
string[]
sehirler = { "Adana", "Adıyaman", "Afyon",
"Ağrı", "Amasya",
"Ankara", "Antalya"
};
foreach (string il in sehirler)
{
lstOgeler.Items.Add(il);
}
Ekran
Çıktısı
Yukarıdaki
örnekte sehirler dizisindeki her bir eleman için dön ve her bir elemanı ListBox
‘ın item ‘larına (elemanlarına) ekle demiş olduk. Koleksiyonun her bir elemanı string
olduğu için tipini en başta belirmiş olduk.
Yukarıdaki
"il" adlı string değişkene "foreach iterator" denir. Bu
yapı döngü nesnesi yardımıyla her bir elemanı tek tek ele alabilmemizi sağlar.
Ancak bu elemana herhangi bir şekilde değer ataması yapmanız mümkün değildir.
Foreach
Döngüsü ile koleksiyon içerisindeki her bir elemana değer atma :
Foreach
döngüsünde sadece ileriye doğru bir iteration (Forward Only) söz konusudur.
Ayrıca içerisindeki iteratioin variable (öteleme değişkeni) Read Only yani
sadece okunabilirdir. Bu nedenle değer atarken bu değişkene değil, bu
değişkenin temsil ettiği elemana değer atanmalıdır.
Öncelikle
hatalı kullanıma bir örnek verelim. Yine “Sehirler” adında, boyutu 7 olan bir
string dizi tanımlayalım.
string[] sehirler = new string[7];
Bu dizinin tüm elemanlarına
“adana” değerini atamaya çalışalım.
foreach (string il in
sehirler)
{
il = "Ankara";
}
Yukarıda
da bahsettiğimiz gibi derleme zamanındaki (Compile Time) hata mesajında da
görüldüğü gibi (Cannot assign to 'il' because it is a 'foreach iteration variable)
”iteration değişkenine değer atanamaz.” hatasını almaktayız. Bunun yerine örneğimizde
koleksiyon olarak dizi kullandığımız
için o dizinin elemanlarına değer atamalıyız. Bunun için kaynakDizi adında
kaynak bir dizi tanımlayalım. Bu dizinin elemanlarını da hedefDizi adındaki
hedef dizimizin elemanlarına atalım. İndex bilgisi için de index adında integer
tipli bir değişken tanımlayalım ve her döngü adımında bu index değişkenin
değerini, ilgili dizinin sıradaki elemanına geçmesi için bir arttıralım.
string[] kaynakDizi = { "Adana",
"Adıyaman", "Afyon", "Ağrı",
"Amasya", "Ankara",
"Antalya" };
string[] hedefDizi = new
string[7];
int index = 0;
foreach (string il in sehirler)
{
//il = "Ankara";
hedefDizi[index] = kaynakDizi[index];
lstOgeler.Items.Add(hedefDizi[index]);
index++;
}
Fakat bu örnek
için for döngüsü daha idealdir. Foreach döngüsü genellikle tanımladığımız sınıf (class) tiplerini koleksiyon şeklinde
tutabilen tiplerin elemanlarında dönmek için kullanılır. Örneğin “urun” adında
bir class tanımlayalım ve ad, stok, fiyat gibi bir takım özelliklere sahip
olsun. Ve herhangi bir ürün nesnesi “get” edilmek (okunmak) istendiğinde “full-qualification
name” (namespace.class) ismi çıkmaması için object sınıfındaki ToString()
metodunu farklı davrandıralım yani aşağıdaki gibi “override” edelim.
public class urun
{
public string ad { get; set; }
public int stok { get; set; }
public decimal fiyat
{ get; set; }
public override string
ToString()
{
return this.ad;
}
}
Her bir elemanı
bu sınıf tipinde olan bir koleksiyon tanımlamak için “List<>” generic
sınıfından faydalanabiliriz. Bu sınıfın “Add” metedu sayesinde koleksiyona
kolay bir şekilde eleman ekleyebiliriz, tabi ki şart tipi ürün olması
gerekiyor.
List<urun>
urunler = new List<urun>();
urunler.Add(new urun
{ ad = "Domates", fiyat = 2.5m,
stok = 100 });
urunler.Add(new urun
{ ad = "Biber", fiyat = 1.5m, stok
= 250 });
urunler.Add(new urun
{ ad = "Patlıcan", fiyat = 2.0m,
stok = 50 });
Artık elimizdeki
bu koleksiyonun elemanlarında foreach kullanarak dönebiliriz, değerlerini
okuyaabilir herhangi bir kontrole yazdırabiliriz.
foreach(urun
u in urunler)
{
listBox1.Items.Add(u);
}
“urunler”
koleksiyonun içerisindeki her bir elemanın tipi “urun” olduğundan dolayı tip
belirtildi. Artık bu elemanlara foreach içerisinde “u” adıyla seslenilecektir.
Herhangi bir ListBox kontolüne eklediğimizde urun sınıfındaki “ToString” metodu
çalışarak ürünün adı görünecektir.
Buradaki asıl dikkat
edilmesi gereken nokta foreach döngüsüni kullanarak herhangi bir koleksiyonda
dönebilmek için o koleksiyonun .Net ortamında “IEnumerable” interface ‘ini
implamente almış olması gerekir. Çünkü bu interface içinde “GetEnumarator”
adında bir metod bulunur ki bu metod da IEnumerator interface ‘ini implemante
almıştır. IEnmarator interface ‘i içerisinde ilgili sınıf nesnesinin foreach
döngüsünde döenebilmesini sağlayan 3 adet metod bulunur: Current, MoveNext,
Reset olmak üzere. Current foreach içerisinde o anki elemanı teslim eder,
MoveNext sıradaki elemana geçmek için koleksiyonun index ‘ini 1 arttırır.
Sırada eleman varsa true sonucu döner ve o eleman get edilmek istendiğinde yine
Current metodu çalışacaktır. Sırada eleman yoksa da false dönecektir ve index
değerini -1 yapan yani döngüden çıkılmasını sağlayan Reset metodunu
çağıracaktır. Custom yani geliştirici tanımlı normal ya da generic koleksiyon
tanımlamasını ilerleyen yazılarımda anlatacağım. Örneğin List tipine sağ
tıklayıp “go to defination” seçeneğini seçtiğimizde “IEnumarable” interface
‘ini implemante almış olduğunu görüyoruz.
Ya da c sharp
‘ta “ComboBox.ObjectCollection” ve ya “ListBox.ObjectCollection” gibi
IEnumerable interface ‘ini implamente almış (uygulamış) olan özel koleksiyon
tiplerinin elemanlarında dönebilmek için de kullanılabilir. Hemen bir örnek
üzerinde görelim:
foreach (urun
u in listBox1.Items)
{
if (u.ad == "Domates")
{
MessageBox.Show("5 kilo al!");
}
}
ListBox ‘ın item
‘larının da .Net ‘deki tanımlamasına gittiğimizde IEnumerable interface ‘ini
implamente almış olduğunu görürüz.
Diğer bir örnek,
formunuzdaki tüm TextBox ‘ların Text özelliklerini temizlemek isteyebilirsiniz.
Bunun için teker teker TextBox ‘ların textini temizleyeceğinize aşağıdaki gibi
foreach döngüsünü kullanarak, formun kontrollerinde gezip, eğer bu kontrol TextBox
ise textini temizle diyebilirsiniz. Tabi ki bir tip kontrolü yapılırken “is”
anahtar kelimesiyle yapılmalıdır. Ayrıca "Controls" koleksiyonu bize formun üzerindeki tüm kontrolleri Control tipinde teslim edecektir. Fakat dikkat edilmesi gereken nokta TextBox
‘ın Text özelliğine erişebilmek için elde ettiğimiz kontrolü TextBox ‘a “cast”
etmeliyiz ki; o kontrol TextBox gibi davranabilsin. Böyle TextBox nesnesinin “Clear”
metodu sayesinde TextBox ‘in texti temizlenebilir.
foreach (Control
ctrl in this.Controls)
{
if (ctrl is
TextBox)
{
(ctrl as TextBox).Clear();
}
}
“This” anahtar
sözcüğü kullanıldığı sınıfın nesnesini temsil eder. (Bu yüzden static
sınıflarda “this” sözcüğü kullanılmaz.) Bu örnekte “this” sözcüğünü, Form1
sınıfı içerisinde kullandığımız için, bu sınıfın bir öğesi gibi davranacaktır.
“Controls” koleksiyonunun .Net ortamındaki tanımına gittiğimizde yine
IEnumerable interface ‘ini implamente almış olduğunu görürüz.
IEnumerable ve IEnumarator interface kullanımı daha sonraki makalelerimde ayrıntılı bir şekilde ele alacağım. Başka bir yazıda görüşmek dileğiyle, hoşçakalın...