27 Haziran 2010 Pazar

Generic Kisitlamalar

Generic kisitlamalarda tip kisitlamasi yoktur. Yani

Class Ornek< T >
{
}

dersek, T yerine tum tipler gelebilir. Ama bazi durumlarda tip kisitlamasi yapmak isteyebiliriz. Ornegin, yas bilgisi isteyen bir metodumuza string gelmesin diyebiliriz, daha dogrusu referans turlu bir deger girilmemesini isteyebiliriz. Bu tarz kisitlamalari su sekilde olusturuyoruz;

class SadeceRefTurluler< T > where T:class
{
//T: sadece referans turlu tipler gelebilir.
}

class SadeceDegerTurluler< T > where T : struct
{
//T yerine sadece deger turluler gelebilir.
}

class SadeceDbConnectionYadaOndanKalitilanlar< T >where T : DbConnection
{
//T yerine DbConnection ya da DbConnection'dan kalitilan herhangi bir tip gelebilir.
}

class SadeceForeachIleGezilebilenler< T > where T : IEnumerable 
{
//T yerine sadece IEnumerable interface'nin implement eden bir tip gelir.
}

class X< T > where T : new() //bunu yazmazsak ide bizim T ile ornekledigimiz metodun abstract olmadigini veya parametre alan bir ctor oldugunu varsayabilir.
{
//Abstract olamaz.
//Default Ctor'i olmak zorunda

T yeni = new T(); //sorun olusmaz
}

C#'da Generic Kavrami

C# 2.0 ile birlikte hayatimiza giren ve bir daha da cikmamasini istedigimiz Generic siniflari uygulamalarimiza buyuk kolaylik getiriyor. Kisaca aciklamak gerekirsek, kendileri tiplerden bagimsiz nesne tasarimlari ve metot yazimlarini olusturmamizi sagliyor. Iyice acmak gerekirse, biz class veya metot yazarken ornegin kullanicinin girecegi tipin nesne tanimlamasi sirasinda belirlenmesini isteriz. Kisaca kod uzerinde soyle tanimlarsak;

public static void DegerAl(int a) //burada kullanicidan nesne orneklenmesi sirasinda int deger aliriz.
{
}

integer girmek zorunda olmasin kullanici. String deger de girebilsin. Ne yapmamiz gerekecek bu sefer, ayni class isminden string bir parametre alan baska bir fonksiyon alacagiz, yani overload edecegiz. Kullanici daha sonra double girmek istesin, daha sonra char, sonra byte ... iste gordugunuz gibi tum girilen degerler icin overload etmek zorunda kalicaktik. 10-15 overload metodun yaptigini tek satirda Generic Siniflarin yardimiyla yapacagiz simdi.

public static void DegerAl< T >(T t)
{
}

Burada T tipinden bir parametre istedigimizi belirtiyor. T yerine string, int .... tum tipler gecerli olacaktir.



Yukarida da goruldugu gibi obj2. dedigimiz zaman intellisense bizden string deger isteyecek, cunku yukarida yerine string yazmistik biz.



Yukarida da gordugunuz gibi T yerine int yazdigimiz zaman parametre olarak da intellisense bizden artik T degil int bir deger girmemizi istiyor. Oraya string yazsak bizden ayrica string bir deger isteyecekti.
Ayrica asagidaki iki screenshot'i incelemekte fayda var. Buradan da anlayacagimiz uzere intellisense bize buyuk kolayli sagliyor gordugunuz uzere.
1-

2-



26 Haziran 2010 Cumartesi

C#'da Ozel Interfaceler(IComparable, IComparer, IDisposable, ICloneable))

C#da kullandigimiz metotlarin,property'lerin vs. arka planda nasil bir gorev yaptiklariyla pek ilgilenmeyiz genelde.sayi.ToString() der geceriz. Yada daha onceki makalelerde de oldugu gibi foreach(int a in dizi) diyip elemanlari yazariz direk. Fakat C#'da tum gorevler icin framework'de aslinda oldukca onemli atamalar, metot cagirimlari vs. yapiliyor aslinda. Simdi bunlarin en onemlilerini kisaca yazmaya calisacagim.

IComparable: Bizim nesnelerimizi karsilastirmamizi saglayan koddur. int a=5 ile int b=6'yi karsilastirmak kolay fakat biz kendi yazdigimiz Urun sinifini karsilastirmak istersek ne yapacagiz. Kisaca yapmamiz gereken Urun classini IComparable'dan implement edip,

class Urun:IComparable

IComparable'ye ait CompareTo metodunu kendi algoritmamiza uyarlamak.

public int CompareTo(object obj) //ArraySort metodu ile geldi buraya
{
Urun gelen = (Urun)obj;
//Gelen nesneleri Fiyat ozelliklerine bakarak siraladik..
if (Fiyat > gelen.Fiyat) return 1;
else if (Fiyat <>
else return 0;
}

Bizim Urun nesnemiz su sekilde olsun diyelim ki;
Urun[] urunler = { new Urun(1, "Monitor", 200), new Urun(2, "Klavye", 80), new Urun(3, "Mouse", 100) };
Buna gore eger biz
Array.Sort(urunler);
dersek, bizim Urun sinifinda yazdigimiz ve IComparable interfacesini implement ettigimiz icin olusturdugumuz CompareTo() metodu cagrilacak ve karsilastirmalar sonucunda 1,-1 ve 0 degerini dondurecek.Kisaca yaptiklarimizi maddeler halinde yazmak istersek;

  • Sort metodu, gelen dizinin icinden belli bir siralama algoritmasi kullanarak, her defasinda iki elemani secer!
  • Bu iki elemani CompareTo metodundan gelen sonuca bakarak karsilastirir ve gelen sonuca gore elemanlari siralanmasini saglar.
  • Sort metodunun calisabilmesi icin gelen dizideki tum elemanlarin karsilatirilabilir tipler olmasi gerekmektedir.Yani Icomparable interface'ini implement etmesi gerekir.
Array.Sort(urunler); sonucunda da urunler dizisini nasil karsilastirma yapacagini bilmedigi icin biz compareto metodunu implement ettik ve biz aslinda yeni bir metot yazdik. buna gore bizim sectigimiz uzere fiyatlara gore karsilastirma yapacagiz artik.

IComparer: IComparable olmayan ve buna izin verilmeyen classlar icin uygulanir. Ornegin SqlConnection sinifini hic bir sekilde karsilastirma yapamayiz. Ama bu metot sonucunda bunu yapabilir duruma gelecegiz.

class SqlConnectionComparer:IComparer

IComparer'i implement ettigimiz icin Compare metodunu tekrar icini doldurmamiz gerekecek;

public int Compare(object x, object y)
{
//gelen connectionlarin ConnectionStringlerine bakalim ve alfabetik siraya koyalim.
SqlConnection c1 = (SqlConnection)x;
SqlConnection c2 = (SqlConnection)y;
return c1.ConnectionString.CompareTo(c2.ConnectionString);
}

ConectionString bize string bir deger dondurdugu icin ve stringleri de biz karsilastirma yapabildigimiz icin, ayni zamanda da string IComparable oldugundan CompareTo metodu oldugunu biliyoruz. Onu cagirirsak karsilastirmayi yapabilmis oluruz..
SqlConnection nesnemiz de su degerlerden olussun;
SqlConnection[] baglantilar =
{
new SqlConnection("InitialCatalog=AdventureWorks"),
new SqlConnection("Server=localhost"),
new SqlConnection("server=."),
new SqlConnection(""),
};
Array.Sort(baglantilar, new SqlConnectionComparer());
IDisposable: Bu interfacemiz de kisaca, GarbageCollector'dan fazladan duran nesneler silinirken yapmasini istedigimiz islemi belirtiriz. Ornegin; programi kapatmak istedigimiz zaman yaptigimiz islemleri kaydetmek isteyip istemedigimizi sormasi gibi programin. Bu interface de yine ayni sekilde Dispose metodunu bize icini doldurmaya mecbur kilar. Bu interfaceyi kullanmak istiyorsak yazmis oldugumuz class'i IDisposable'a implement edip Dispose() metodunun icini doldurmamiz gerekir.

ICloneable: Isminden de anlasilacagi uzere bir nesneyi klonlamak istersek, yani ayni nesneyi farkli adreste tutmak istersek kullanmamiz gereken interface'dir. Clone() metodunu getirir bu interface de.

C#'da Interface(Arayuz) Kavrami

Interface'in tanimini yapacak olursak, kisaca butun uyeleri abstract olan class'lardir diyebiliriz. Peki neden kullanilma geregi hissedilmis. Bunun nedenini de soyle aciklayabiliriz. Ornegin ucabilen ve yuzebilen classlarimiz olsun. Bu classlardan tureyen uyelerimiz olsun. Ornegin ucabilen sinifindan kalitilan kus ve yuzebilen sinifindan kalitilan vapur isimli uyelerimiz olsun. Bizim ayrica karabatak gibi bir uyemiz daha olsun. Fakat istegimiz bu karabatak'in her iki class'tan da uretilmesi. C# dahil hic bir programlama dili coklu kalitima bu sekilde izin vermez. Burada yardimimiza Interface'ler kosuyor.Buna gore yeni yapimiz su sekilde olacaktir. Canli ve Cansiz classlarindan kalitilan kus ve vapur classlari olacak, ayni zamanda karabatak da canli class'indan tureyecek ve IUcabilir ve IYuzebilir interfacesini implement edecek.

Abstract, gorevlerinden de cikaracagimiz uzere public ve abstract olmak zorunda. C# intellisense'nin bize getirdigi kolaylik sayesinde bize sen iki saat bunlari yazma ben senin yerine yazarim diyor. Kisaca nasil tanimlaniyor bir interface?

Interface IYuzebilir
{
Void Yuz();
}
Buna gore bundan sonra herhangi bir ders IYuzebilir interfacesini implement ederse Yuz() metodunu da kullanmak zorunda kalacak. Karabatak icin bu tanimlamayi gosterelim;

public class Karabatak : Canli, IUcabilir, IYuzebilir
{
public void Uc()
{
Console.WriteLine("Karabatak ucuyor.");
}
public void Yuz()
{
Console.WriteLine("Karabatak yuzuyor...");
}
}

Buradan da anlasilacagi uzere bir class'a birden fazla interface uygulanabilir. Bunlarin tanimlamada kullanildiklari sira onemli degildir.

C#'da GetHashCode Kullanimi

GetHashCode, kisaca hangi nesne uzerinden cagrilmissa o nesneye ait bir tamsayi deger ureten komuttur. Bu degeri olustururken iki ayrintiya dikkat eder CLR;

-Eger nesnemiz deger turluyse, direk degiskenlerin sayi degerlerini bize getirir.Yani;

int a=6;
int b=6;
int sayi1=a.GetHashCode();
int sayi2=b.GetHashCode();

dedigimiz zaman sayi1 ve sayi2'nin 6 olarak atandigini gorecegiz.Cunku burada a ve b int turunden, yani deger turlu oldugundan direk bize sayisal degerlerini geri donduruyor.

-Eger nesnemiz referans turlu olursa, bu sefer de tahmin edebileceginiz uzere tuttugu referans, yani kendi adresine gore bir int deger uretir. Yani;

Urun ur1=new Urun(1,"Monitor",200);
Urun ur2=new Urun(1,"Monitor",200);


GetHashCode()'larini calistirdigimiz zaman farkli kodlar uretildigini gorecegiz. Bunun nedeni, her ne kadar ayni degerleri tutsalarda, "new" keyword'u sonucunda ram'de tekrar farkli adreste nesne yaratilmasidir. Yani ur1 ve ur2 farkkli adresleri tuttugundan farkli kodlar uretilir.

Bu bilgiler isiginda su soru gelebilir aklimiza. Neden bu nesnelerin int. kodlarini uretme ihtiyaci duyuyoruz?
-Cevabimiz cok basit, iki nesneyi karsilastirmada en hizli yol her zaman integer'larda olur. Burada da iki nesneyi karsilastirmak icin nesnelerin GetHashCode()'larini karsilastiriyoruz.

NOT: object ve string'lerin referans turlu olduklarini biliyoruz. Ama C#'da sunu her zaman hatirlamaliyiz ki, object ve string atama islemlerinde deger turlu ozellik gosterirler. Yani;

object a="abc";
object b="abc";

dersek a ve b'nin farkli adresleri tuttugunu goz onunde bulundurup farkli hashcode'lar bekleriz ama derledigimiz zaman gorecegiz ki a ve b icin olusturan kodlarin ikisi de ayni. Buradan da su sonucu cikarabiliriz ki object ve string atama islemlerinde deger turlu ozellik kazanir...

19 Haziran 2010 Cumartesi

Karsilastirilabilir Tipler Yazmak- CompareTo(IComparable)

Bazen elimizde olan verileri siralamak isteriz en basitinden. Bunu yaparken kullandigimiz komutlarin arka planda nasil calistiklarini bilmeyiz. Direk array.sort der geceriz, ama bilmeyiz ki gunun birinde elimizde siralanmasi mumkun olan ama ilk gorunuste siralanmayacak veriler olabilir. Iste o zaman fildir fildir nasil siralayacagiz bunlari diye nette arama yapariz, yada "ulan array.sort'un calisma mantigi ne acaba" diye sorariz. Kisaca bu sorunlara cozum bulmaya calisalim.

int[] sayilar = { 4, 5, 12, 6 }; //Amac: Sayilar dizisini artan siralamak.
Array.Sort(sayilar);

Iste yapmamiz gereken sadece tek satirda siralama yapan kodu cagirmak. Yazdigimiz kod da bunu yapiyor zaten, yapmamiz gereken sey siralanmis diziyi yazdirmak.
foreach (int s in sayilar)
{
Console.WriteLine(s);
}
Console.WriteLine("**********");

Ekran ciktisi su sekilde olacaktir.


Kodlari ILDisassambler ile inceledigimiz zaman aslinda array.sort dedigimiz zaman IComparable interfacesinin CompareTo metodunu calistirip orada gerekli islemlerle artan siralama yapiliyor. Peki bizim elimizde siralanamayacak turden veriler olursa, yani IComparable interfacesini implement eden bir nesne yoksa siralamayi nasil yapacagiz?

Elimizde su classlar oldugunu varsayalim;
Urun[] urunler = { new Urun(1, "Monitor", 200), new Urun(2, "Klavye", 80), new Urun(3, "Mouse", 100) };
Array.Sort(urunler);
Array.sort dedigimiz zaman urunler classini siralayamacagini goruyoruz. Bunun icin yapmamiz gereken sey bizim kendimiz CompareTo metodu olusturup, yazacagimiz class'i da IComparable interfacesinden implement etmemiz gerekecekti. Kisaca ustte yazdiklarimizi daha acik bir dille ozetlemek gerekirsek;
  • Sort metodu, gelen dizinin icinden belli bir siralama algoritmasi kullanarak, her defasinda iki elemani secer!
  • Bu iki elemani CompareTo metodundan gelen sonuca bakarak karsilastirir ve gelen sonuca gore elemanlari siralanmasini saglar.
  • Sort metodunun calisabilmesi icin gelen dizideki tum elemanlarin karsilatirilabilir tipler olmasi gerekmektedir.Yani Icomparable interface'ini implement etmesi gerekir.
O zaman kisaca biz ustteki urun dizisi icin bir CompareTo metodu yazalim. Bunun icin ustte de belirttigimiz gibi IComparable interfacesinin implement etmesi gerekecek.
class Urun:IComparable

public int CompareTo(object obj) //ArraySort metodu ile geldi buraya
{
Urun gelen = (Urun)obj;
if (Fiyat > gelen.Fiyat) return 1;
else if (Fiyat <>
else return 0;
}
1 , -1 ve 0 degerleri CompareTo metodunun kendi icinde bulunan algoritmadir. Bunu yine kendimize gore uygulayabilirdik.

Bu kodlamalardan sonra da yapmamiz gereken tek sey foreach ile dizide donup elemanlari ekrana yazdirmak.
foreach (Urun urn in urunler)
{
Console.WriteLine(urn);
}
Hemen ek bir bilgi daha verelim, ekrana biz urun ismi ve fiyatlari gostermek istiyorsak, yine ayni sekilde ToString metodunu override ederek object.ToString sinifini ezmis olur ve boylece kendimiz istedigimiz degerleri ekrana yazdirabiliriz. Yani;
public override string ToString()
{
return Ad+","+Fiyat;
}
Buna gore ekran ciktimiz asagidaki sekilde olacaktir.


12 Haziran 2010 Cumartesi

Sorted List - Hash Table

Daha once kisaca koleksiyon kavramindan bahsetmistik ve ornek olarak ArrayList hakkinda kisaca konusmustuk.Simdi diger koleksiyon kavramlarini inceleyecegiz.

Sorted List:

Sorted list'ler sozluk tabanli koleksiyonlardir. Kisaca sozluk tabanli koleksiyonlar, Elemanlarin eklenmesi sirasinda, key degeri de isteyen koleksiyonlardir.(Dictionary Base). Sozluk tabanli koleksiyonlar, indexle okumaya alternatif yaratarak elemanlarin key degerleriyle elde edilebilmesini saglar.

SortedList SiraliListe = new SortedList();
SiraliListe.Add(34, "Istanbul");
SiraliListe.Add(6,"Ankara");
SiraliListe.Add(41,"Kocaeli");

Sorted list kullaniminda elemanlar kendi iclerinde KEY degerlerine gore artan siralanir. Yani bizim girdigimiz ilk deger Istanbul olmasina ragmen daha sonra gelen Ankara'nin key degeri daha kucuk oldugundan 1. siraya Ankara gecer.

Indexe gore cagirmak istersek de;

Console.WriteLine(SiraliListe.GetByIndex(0));//0. indexindeki degerini getirir.

foreach (DictionaryEntry obj in SiraliListe) //hem key hem de value'nun icinde gezmek istersek DictionaryEntry bu tipi kullanmak zorundayiz.
{
Console.WriteLine("{0},{1}",obj.Key,obj.Value);
}
HashTable:
  • Sorted list gibi sozluk tabanli bir class'tir.
  • Icine eklenen elemanlari, en hizli erisilebilecek sekilde siralar.
  • Bize anlamli gelen (Ornegin key'lere gire artan, valuelara gore azalan gibi) bir siralama yapmaz.
  • Ancak eklendigi gibi sirayla da birakmaz, yani bir siralama yapar.
  • Hashtable ozel bir siralama algoritmasi,koleksiyonu nesnelere en hizli erisim yapabilecek hale getirir.


As ve Is Operatoru

As Operatoru: cast operatoru,bilincli atama sirasinda bir tip uyusmazligi varsa, exception firlatir.

object nesne = new Program();
string kelime = nesne as string;

nesne eger string degilse exception vermez null doner. Referans turluler null deger aldiklarindan sadece ref turlulerde kullanabiliriz as operatorunu.

Is Operatoru: Calisma aninda isaret edilen nesnenin tipini kontrol etmemizi saglar...

if (nesne is Program)
{
Console.WriteLine("Program tipinden bir nesneyi isaret etmekte.");
}

Abstract Class'lar

Abstract class'i tek cumlede anlatmak istersek, kisaca kendinden turetilen siniflara base class olan siniflara abstract class'lar adi veriliyor. Satir satir abstract class'lar hakkinda bilinmesi gerekenleri yazdigim zaman daha iyi anlasilacaktir.

-Abstract bir class icinde yazilan Abstract metod, kendinden turetilen tum siniflarda kullanilmak zorundadir.
-Nesnesi yaratilamaz.
-Her abstract bir Virtual Class'dir diyebiliriz.
-Abstract metotlar sadece Abstract Class icinde yazilabilir.

abstract class EvcilHayvan
{
public abstract void SesCikar();
}

Bir onceki bilgilerimizi de kullanarak sunu soyleyebiliriz ki;

-Eger turetilen siniflan ve tureten sinif ayni ozelliklere sahipse --Inheritance--
-Turetilen siniflarin bazilari ayni gorevlere sahipse --Virtual--
-Turetilen siniflar ayni gorevde fakat tureten sinif ayni goreve sahip degilse Abstract'tir
diyebiliriz.

Virtual (Sanal) Class'lar

Kisaca virtual classlar, c#'da isaret edilen nesneye ulasmamiz gerektiginde kullanmamiz gereken classlardir.

Silindir s;
Daire alan=s;
dersek daire sinifinin uyelerine erisir.ama biz belki de silindirin alanina erismek istiyorduk. Bu yuzden, eger AlanHesapla metodumuz, silindir ve daire icin ortaksa bizim ayri ayri metot tanimlamamiza gerek kalmaz. Zaten silindir daireden turemisti ve orada yaricap, merkez gibi bilgileri almisti. Bunlari ayni metot ismi uzerinden kullanip, yani override islemi yapabiliriz.Yani;

Public virtual double AlanHesapla();
dersek dairenin AlanHesapla isimli metoduna,

Public override double AlanHesapla();
dersek de ustteki koddan silindirin AlanHesapla isimli metoduna erisiriz.

Buradan da anlasilacagi uzere, turetilen siniflarda ayni gorevi yapan metotlarin sadece govdesini degistirerek ayni isimde gorev verebiliriz. Bunun icin yapmamiz gereken tek sey override sozcugunu eklemek.

4 Haziran 2010 Cuma

Parse ile Convert.ToInt Arasindaki Fark Nedir?

Kisaca cevaplarsak;

Parse metodu, girilen degerin null olup olmadigina bakmadan direk calisiyor. Dolayisiyla null olmasi durumunda hata verdiriyor. Buna karsilik;

Convert.ToInt metodu, girilen degerin null olup olmadigini kontrol edip, nullsa degerin null oldugunu yazdiriyor, degilse de daha sonra parse metodunu cagirarak gereken islemi yaptiriyor.


Koleksiyon Kavramlari(ArrayList)

C# da ve daha dogrusu butum programlama dillerinde bilgileri elde tutmanin en kolay yolu dizilerdir. Fakat bazi durumdlarda diziler de yetersiz kalabilmektedir. Nedir bu durumlar? Bir listeye ortadan deger girmek veya 4 elemanli bir diziye eleman ekleyememek ... vs. gibi sorunlar. Bu durumda yardimimiza koleksiyon kavrami kosuyor. Simdi kisaca ornek uzerinden de anlatalim.

Arraylist dedigimiz kavrami boyutsuz dizi gibi de tanimlayabiliriz. Aslinda boyutu var, ilk acilista otomatik olarak 4 byte olarak acilip, listemiz dolduktan sonra eklenen eleman icin 2 kati uzunlugunda yer daha aciyor kendisine. Bunu 4 byte olarak secmesinin nedeni de sonucta dizinin boyutunu artirmak da bilgisayar icin zahmetli bir yol oldugundan surekli 1 byte 1 byte veri ekleyecegine, tek seferde 4 acip daha sonra 2 ser kati artarak daha az yakit kullanarak daha cok yol almis oluyor.

Konudan uzaklasmadan, arraylist'leri dizi mantiginda dusunursek, tanimlamamiz yine ayni sekilde olacak, bellege yeni adresini acmis olacagiz.

ArrayList liste = new ArrayList();


NOT: koleksiyon kavramini kullanabilmemiz icin mutlaka namespace'sine su tanimlamayi yazmamiz gerekir.

using System.Collections;

Artik namespace'miz de hazirsa yeni dizimize(koleksiyon) deger girisi yapalim.

liste.Add("Istanbul");
liste.Add("Ankara");
liste.Add("Izmir");

//Indexer kullanımıyla atama
liste[1] = "Trabzon";
//ve okuma
Console.WriteLine(liste[1]);

Son olarak da sunu unutmayalim ki, listeye deger girisi yaparken veya deger okuturken arraylist'in bizden object bir deger istedigini gorecegiz. Bizim programa hangi tipin(int,string,double,char...vs) gelecegini ozellikle belirtmemiz gerekir ki orda da casting islemleri devreye giriyor.