C# etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
C# etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

30 Temmuz 2011 Cumartesi

Tek Satırda If Komutu

If-Else yapılarının tek satırda toplanmış hali;


   sonuc = (sayi%2==1) ? "Tek":"Çift";
   
Yapısı kısaca,  

(koşul ifadesi) ? "True" : "False";

20 Temmuz 2011 Çarşamba

C# Dosya Yazma-Okuma İşlemleri(Input-Output)

C#'da uygulama geliştirirken çokça kez bir dosyaya veri yazma, veya bir dosyadan veri okuma gibi ihtiyaçları hissederiz. Şimdi size, basit olarak en kısa yoldan, bir dosyadan veri okunmasını ve yazılmasını anlatacağım.

Öncelikle dosyadan veri okuma ve yazma işlemlerimizi yerine getiren 2 sınıfımız var. Veri okuma işlemleri için, StreamReader,veri yazma işlemleri için de StreamWriter classlarını kullanırız. Kısaca kodlar üzerinden anlamaya çalışalım.

1-Veri Okuma :


FileStream file = new FileStream(@"C:\\ergin2.txt", FileMode.Open, FileAccess.Read);
StreamReader read = new StreamReader(file);


FileStream classının constructorında, sınıfa parametre olarak sırasıyla, dosyanın yolu,dosya belirtilen yolda bulduktan sonra hangi işlemi yapacak (burada açmasını istedik),üçüncü parametre olarak da bu dosyanın okunacağını belirtiyoruz. Ardından, verileri okumamızı sağlayan StreamReader sınıfına bu dosyamızı veriyoruz.


string s = "";
string line = "";

while ((line = read.ReadLine()) != null)
{
       s += line + ",";
}
if (s.Length > 1)
s = s.Substring(0, s.Length - 1);


Ardından, senaryomuza göre dosyada satır satır bulunan id'leri ReadLine() metodu sayesinde okuyup, son satır gelene kadar aralarına virgül koyarak ayırıyoruz. En son satırda da virgül olacağından, o virgülü silmek için de substring metodunu kullanıyoruz. Böylece, örnek dosyamızda;

123
456
789
...
şeklinde olan veri;

123,456,789

şeklinde okunacak.

2- Veri Yazma :



StreamWriter sw = new StreamWriter(@"C:\\ergin2.txt", true);

sw.WriteLine(txtId.Text);


Burada da, yine aynı şekilde, önce StreamWriter nesnemizi oluşturduk. Yalnız, burada dikkat etmemiz gereken nokta, StreamWriter'in string ve bool parametresini alan overload'ını kullanmamız gerekir. Aksi taktirde, veri okurkenki gibi 3 parametreli overload'ını kullanırsak, dosyamıza append edemeyiz verilerimizi. Yani verilerimiz sürekli üst üste yazılacağından, biri silinirken diğeri yazılacak, dolayısıyla sadece en son veri ekranda yazılmış olacak. Bu yöntemle, ikinci parametreye true vererek, append işlemi yapmak istediğimizi söylüyoruz ve TextBox'ımızın içinde yazan değeri de yazmış oluyoruz belirttiğimiz dosyaya.

Görüldüğü gibi, veri okuma ve veri yazma işlemleri oldukça kolay. Yapmamız gereken, FileStream nesnesini oluşturup, veri yazılacak veya okunacak dosyayı tanıtıp, hangi işlemleri yapmak istediğimizi belirtip, bizden istenen işleme göre (okuma-yazma) StreamReader veya StreamWriter classlarını kullanıp, gerekli metotlar sayesinde istediğimiz işlemleri yapmak olacaktır.

2 Nisan 2011 Cumartesi

C#'da Shared Assembly Oluşturmak

Assembly kısaca; kaynak kodun, derleyiciden cikmasiyla olusan dosyadir. Uzantisi iki farkli sekilde olur. dll yada exe'dir. dll, bilindiği gibi, projemize referans eder, içindeki hazır fonksiyonları, classları vs. kullanırız. exe ise, oluşturduğumuz uygulamanın çalışmasını sağlayan dosyaydı. Bu iki bilgi çok temel bilgidir fakat eksik şeyler var aslında burada. Öncelikle, .Net 2.0 ile birlikte 2005 yilindan sonra artik exe'ler de projeye referans edilmeye basladi. Peki bu dll,exe dosyaları nerede bulunur. Projemizin oluşturulduğu klasörü açtığımız zaman, bin klasörü içinde bulunan debug klasörünün içinde yer almaktadırlar dll ve exe. Aslında pdb uzantılı dosyalar da mevcuttur ama pek bilinmez ve kullanılmazlar. Yine de söylemek gerekirsek,  kısaca bu dosyalar da, debug yaparken bazı loglamaların saklandığı dosyalardır.

Bu bilgiler eşliğinde, şundan da kısaca bahsetmek gerekir. Bazı dll'ler, Visual Studio'yu ilk açtığımız andan itibaren kendiliğinden referans edilmiştir. Hatta biz onları references'dan silsek bile hata verilmez. Bunların dışında, kendi elle verdiğimiz dll'lerde mevcuttur. Tüm bu dll'ler .Net Framework içinde olabileceği gibi, daha sonradan oluşturulup, kullanılmak istenen dll'ler de olabilir.

İşte .Net dilinde, hazır framework içinde bulunan dll'lere Shared Assembly, Kendi yazdığımız,  sonradan oluşturulmuş dll'lere de Private Assembly denir. Private Assembly'ler kullanıldığı yerin yanında olmak zorundalar. Shared Assembly'ler için böyle bir zorunluluk yoktur. Yukarıda dediğim gibi, references'dan silsek bile o dll'i hata çıkarmaz. Bu dll'lere örnek verecek olursak, en başta System.Data dll'i gelir.

Shared Assembly'lerin bulunduğu/saklandığı yere GAC denir. Açılımı Global Assembly Cache'dir.

Şimdi biz de kendi yazdığımız dll'i(Private Assembly) Shared Assembly haline getirelim. Bunun için yapmamız gereken  ilk özellik, bu dll'e strong name (yani ona özgünlük sağlayacak) bir isim vermek olmalıdır. Bu isme de , projemize sağ tıklayıp properties dedikten sonra signing kısmından erişiyoruz.


Gördüğünüz gibi, mykey.snk isminde strong name oluşturdum.

Daha sonra da Visual Studio'nun Command Prompt ekranını açıp (Başlat-All Programs-Microsoft Visual Studio2010-Visual Studio Tools-Command Prompt) şu komutları yazmalıyız.



12 Şubat 2011 Cumartesi

C#'da yield Kavrami

Daha onceki makalelerde Foreach iterasyonu hakkinda bilgi vermistim. Kisaca hatirlatacak olursak, IEnumerable interfacesini implement etmeyen bir class foreach iterasyonuna sahip olamiyordu. Bunun icin, o class'i IEnumerable interfacesinden implement edip, bu implementle birlikte override edilmesi gereken GetEnumerator metodunun icini doldurdugumuz zaman, artik bizim yazdigimiz sinifta da foreach ile gezebilecek duruma geliyorduk. Sunu da unutmayalim ki, GetEnumerator metodunu override ederken, MoveNext(), Reset() metotlarini ve Current isimli uyesinin iclerini doldurmamiz gerekiyordu.

Mantigi oldukca basit ama bazi projelerde, uygulamaya entegrasyonu sıkıntı çıkarabiliyor. Iste bu  sıkıntıları gidermek için C# 2.0 ile birlikte gelen yield keywordu sayesinde bu islemlerin tumu bizim icin arka planda yapilmis olacak.

Kullanimi oldukca basit;

Yine ayni sekilde, UrunYonetim sinifini olusturup, IEnumerable sinifindan kalitalim ve GetEnumerator sinifini override edelim.


namespace yieldKullanimi
{
    class UrunYonetim : IEnumerable
    {
        Urun[] _urunler;

        public UrunYonetim()
        {
            _urunler = VeriTabanindanOku();
        }

        private Urun[] VeriTabanindanOku()
        {
            Urun[] urunler = { new Urun(1, "Monitor", 200), new Urun(2, "Klavye", 80), new Urun(3, "Mouse", 40) };

            return urunler;
        }

        public IEnumerator GetEnumerator()
        {
            for (int i = 0; i < _urunler.Length; i++)
            {
                yield return _urunler[i].Ad;  
            }
        }
    }
}

Gordugunuz uzere, GetEnumerator sinifinda, onceden bir numarator sinifi olusturup(IEnumerator interfacesini implement eden sinif) nesnesini burada olusturup return ediyorduk. Daha sonra da MoveNext,Reset ve Current gibi uyelerin icini dolduruyorduk. Tum bunlari, GetEnumeratorun icine yazdigimiz kodlar yapiyor iste. for dongusuyle sayesinde, MoveNext metodunun ici yaziliyor. int i=0 diyerek Reset() metodunu cagiriyoruz, yield return_urunler[i].Ad diyerek de aslinda Current field'ini okuyoruz. Bunun sonucunda da, biz Urun sinifinin icinden string tipinden dolasip, urun isimlerini elde edebilecegiz.

Simdi de IL Disassambler(ILDASM) acarak, fiziksel olarak yazmadigimiz halde hangi metotlarin(uyelerin) olusturulduguna bakalim.


Gordugunuz uzere, biz MoveNext,Reset ve Current gibi uyeler yazmamamiza ragmen, yield keywordu sayesinde, arka planda bunlarin yazildigini goruyoruz. Programimiza buyuk olcude rahatlik getiren, is yukunu azaltan ayni zamanda da kod okulurlugu acisindan profesyonel yapisini koruyan yield'lar sayesinde hayat artik daha da guzel. :)

* Resme tıklarsanız, yeni ekranda, orjinal boyutunda erişebilirsiniz.

5 Şubat 2011 Cumartesi

C#'da Foreach Iterasyonu

Uygulama gelistirirken, belli bir dizinin veya koleksiyonun elemanlari icinde gezerken foreach kullaniriz. Foreach ile ekrana yazdirma, deger atama ... vs. gibi yapmak istedigimiz isleri yapariz. Buraya kadar her sey cok normal, direk yazip geciyoruz. Ama, aslinda bilmeyiz ki, foreach ile bu isleri yaparken, arkada IEnumerable interface'sini implemet ediyor, bunun sonucunda IEnumerator tipinden bir GetEnumerator metodunu override etmemizi istiyor ve bu GetEnumerator de kendi icindeki uyelerle bizim foreach ile yaptigimiz isleri yapiyor.

Buraya kadar her sey cok karisik gelmistir. Ufak bir senaryo uzerinden daha iyi anlayacagiz simdi. string,int,ArrayList gibi tipler IEnumerable'i implement ettiginden foreach ile islem yapilmaya uygundurlar. Ya bizim elimizde, bu interface'yi implement etmeyen bir class bulunursa? Iste asil olay burada basliyor.

Diyelim ki elimizde Personel sinifi bulunsun. Personel'in Id'si,Adi ve Maasi bulunsun. Personel nesnelerimiz de su sekilde bulunsun.

Id;Ad;Maas

1;Ali;100
2;Veli;200
3;Deli;300

Bu personel nesnesinin icinde gezip Id'lerini ekrana yazdirmak istersek, basitce su foreach yapisini yazmamiz gerekirdi.



            Personel prs = new Personel();

            foreach (int id in prs)
            {
                Console.WriteLine(id);
            }


Bu islemi yapip calistirdigimizda su hatayi aliriz;

foreach statement cannot operate on variables of type 'ForeachIterasyonu.Personel' because 'ForeachIterasyonu.Personel' does not contain a public definition for 'GetEnumerator'

Bu hatanin sebebi, Bizim yazdigimiz Personel sinifinin IEnumerable interfacesini implement etmeyisidir. Bunun uzerine sinifimiza gelip IEnumerable interfacesini uygularsak, bizden GetEnumerator metodunun icini doldurmamizi ister ve bunun sonucunda foreach ile gezme islemini yapabilmis oluruz.

Fakat bizim senaryomuz, id'ler uzerinden islem yapmak oldugundan; biz once tum personelleri tutup IEnumerable interfacesini implement eden bir sinif yazacagiz, daha sonra da Id'ler uzerinden islem yapan ve IEnumerator interfacesini implement eden bir class yazacagiz.

Bu ana kadar IEnumerator hakkinda konusmadik. IEnumerator interfacesi, IEnumerable interfacesinin bir sinifa uygulandiktan sonra ici doldurulmasi istenen metodun(GetEnumerator) geri donus tipidir. Gorevi,iterasyonu saglamaktir. IEnumerator'un icinde MoveNext,Current ve Reset uyelerini bulundurur. Bu uyelerin iclerini doldurdugumuzda artik bizim yazdigimiz sinif da foreach ile iterasyon yapilabilecek duruma gelecektir.

Ornegimize geri donersek;
PersonelYonetim isminde  bir class yaratip IEnumerable interfacesini implement edersek, bizden IEnumerator tipinden GetEnumerator metodunu doldurmamiz istenecek. Geri donus tipi IEnumerator olmasi, bizim o metotdan IEnumerator interfacesini implement eden herhangi bir uye geri donderebilecegimizi gosterir. O zaman biz de kendi uyemizi kendimiz yaratalim. Bir class acip, IEnumerator interfacesini uygulayip, MoveNext,Current ve Reset gibi uyelerin iclerini dolduralim.

Yeni yazacagimiz class IdNumarator isminde olsun ve IEnumerator interfacesini uygulasin. Uyguladiktan sonra bizden bazi uyelerin iclerini doldurmamizi isteyecek. Nedir bu uyeler ve uyelerin gorevleri;

Current : O anki koleksiyondaki deger geri doner.
Reset : Sayaci -1'e dondurur.
MoveNext: Siradaki elemana ulasmamizi saglar. Sonraki eleman yoksa da false doner, ulasiyorsak ture doner.


class IdNumarator:IEnumerator
    {
        Personel[] _prs; //Personellerimizi bir dizi icerisinde tutalim
        int _sayac;

        public IdNumarator(Personel[] prs)
        {
            _prs = prs;
            Reset();
        }

        public object Current
        {
            get { return _prs[_sayac].Id; } //O anki personelin id'sini geri dondurelim.
        }

        public bool MoveNext()
        {
            _sayac++;
            return _sayac < _prs.Length; //dizinin boyutunu asmamaliyiz.
        }

        public void Reset()
        {
            _sayac = -1; //Once  movenext calisacagindan, sayaci -1 yapmaliyiz, cunku dizi[0] 'dan baslamali.
        }
    }



Simdi yapmamiz gereken tek sey, PersonelYonetim sinifindaki GetEnumerator metodunda bu classimizi orneklemek (Hatirlatma: GetEnumerator metodu, IEnumerator tipini implement eden herhangi bir uyeyi geri donderdiginden, bizim classimiz da IEnumerator'u implement ettiginden kullanabiliriz.)


Personel[] prs;

public IEnumerator GetEnumerator()
        {
            return new AdNumarator(prs);
        }


Tum bu islemlerden sonra, artik biz de Personel sinifimizda foreach ile Id'lerde gezebilecegiz.


            PersonelYonetim personel = new PersonelYonetim(); 
            foreach (int id in personel)
            {
                Console.WriteLine(id);
            }



NOT: Iterasyonlar, belli bir kurala gore bir nesneye ulasmaktir. Dolayisiyla foreachde de her bir iterasyon kurali, bizim icin IEnumerator interfacesini implement eden bir class'tir.(Hatirlatma:Bu makaledeki ornekte, IdNumarator'dur.)

28 Kasım 2010 Pazar

Ref ve Out Anahtar Sozcukleri

C#'ta pek sık kullanılmayan ama gerektigi zaman da hayat kurtarabilecek oneme sahip anahtar sozcukleridir. Kisaca ne ise yaradiklarini ve nasil kullanildiklarini anlatmaya calisacagim.

ref: Metotlara deger yerine referansini parametre gecmek icin kullanilir.

public int Test(ref int p)
{
return p=5;
}

int a=3;
int a=Test(ref p);

ile a'yi 5 elde ederiz.

out: ref ile ayni kullanima sahiptir.

public int Test(out int p)
{
return p=5;
}

int a=3;
int a=Test(out p);

Aralarindaki tek fark, out ile parametrede sadece yazma islemi kullanabilirken, ref ile hem yazma hem okuma secenegine sahip oluruz. Yani;

public int Test(out int p)
{
p=p+5; // burada hata verecektir. okuma islemi yapilamaz
return p;
}

public int Test2(ref int p)
{
p=p+5; //burada hata vermeyecektir, cunku ref anahtar sozcugu bize okuma imkani da taniyacaktir
return p;
}

27 Temmuz 2010 Salı

Lambda Operatoru

C# 3.0 yeniliklerinden biri de lambda operatorudur. Lambda operatorunun aslinda spesifik bir gorevi yoktur. Sadece anonim metot yazarken kullandigimiz komutlarin bazilarini bize kullandirmadan daha basit ve islevsel bir kodlama imkani sunar. Anonim metotlari, biz LINQ'da kullanacagimizdan bazen gercekten cok uzun kodlamalarla karsi karsiya kalabiliriz. Bu durum kodun okunulurlugunu ve ileride yapilacak olan bir degisiklikte kodlamanin bozulmadan degisiklik yapilmasini zorlastiracagindan lambda operatoru sayesinde bu dert ortadan kalkmis olacak. Simdi kisaca nasil kullanildigini ve eski uzun kodlamalari nasil kisalttigini kisaca ornek uzerinden anlamaya calisalim.

delegate void Temsilci(int a);
delegate int IslemHandler(int a,int b);

Temsilci t = delegate(int a)
{
Console.WriteLine(a * a);
};

Bunu lambda operatoru ile yazarsak;

Temsilci t2 = (int a) =>
{
Console.WriteLine(a*a);
};
Lambda kolayliklarindan faydalanmadik henuz.
Lambda ile kisaca yazmak istersek;

Temsilci t3 = a =>
Console.WriteLine(a * a);

Lambda operatoru ile yapilan kisaltmalarda su maddeler dikkate alinir:
  • Parametrelerin tiplerini soylememize gerek yok delegeden biliyo imzasini.
  • Tek parametre varsa parantezlere gerek yok.
  • Metodun icinde tek satir kod varsa suslu parantezlere de gerek yok.
Lambda operatorunu geri deger donen anonim metotlarda da kullanabiliriz;

IslemHandler islem = (int a, int b) =>
{
return a + b;
};
veya daha kisa yazarsak

IslemHandler islem2 = (a, b) => a + b;

delege baglama olayi da su sekilde gerceklesiyor.

islem2 += (a, b) => a * b;

26 Temmuz 2010 Pazartesi

C# 3.0 Yenilikleri - II

1-Object Initializer:
Nesne orneklemesi yapilirken, eger kullanilan class'in constructori asiri yuklenmisse, bizden asiri yuklenen parametrelerin girisi zorlandirilir ide tarafindan. Yani ornegin Urun classimizin constructori su sekilde ise,

public Urun(int id,string ad,double fiyat)

ise biz bu sinifin orneklenmesini yaparken;

Urun urn=new Urun(1,Monitor,100);

yapmamiz gerekecekti. Bu basit bir ornekti. Diyelim ki projemiz daha uzun ve komplike fieldlara sahip olsun, o zaman surekli constructorlari overload mi edecektik. Onlarca constructor mi yazmamiz gerekecekti. Cevap ne yazikki evet. Iste C# 3.0 yeniligi ile birlikte artik bu cevap hayir olacak :) Hemen ornekte gosterelim;

Urun u = new Urun() { Id = 1, Ad = "Monitor", Fiyat = 200 };

Bizim arka planda ayrica 3 parametreli constructor yazmamiza gerek kalmayacak boylece. Ne kadar guzel bir ozellik degil mi?

Not: Bu ozellik bize ctor'u kullanma demek olmuyor. Ctor'larin isimize gercekten buyuk olcude yarayan cok onemli gorevleri vardir, bu gorevlerden yararlanmak istedigimiz zaman kullanabiliriz. Peki nedir bu gorevler;
a)Kullaniciyi deger girmeye zorlamak
b)Nesne orneklenirken bir takim kodlari calistirabilmek.
2-Extension Methods: Extension metod bir nesne uzerinde is yapan static bir metodu, sanki o nesnenin nonstatic bir metoduymus gibi cagirma imkani saglar.

public static void BenHerYerdeCikarim(this object obj)
{
//toString() gibi tum object nesnelerde gorulebilecek.
}
public static void Test(this IComparable obj)
{ }

* this anahtar sozcugu sayesinde o tipe ait nesnelerin bir uyesi gibi artik intellisensede bize gorunecektir. Yani biz object a; veya IComparable a; diye tanimlama yaptiktan sonra a. dersek intellisensde BenHerYerdeCikarim veya Test metotlarini gormus olacagiz. BenHerYerdeCikarim metodu object siniflara eklendiginden ToStrign() metodu gibi tum nesnelerde cikabilecek.

Butun bu uyeler (object,IComparable ... vs.) turetmeye uygun class olduklarindan biz bunlari turetip, bu classlara kendi metotlarimiz ekleyebiliyorduk. Peki bizim classimiz kalitim dusmani olan sealed olsaydi. Hemen en basit ornegi

Public sealed class String;

Stringleri kalitamadigimizdan o sinifa metot da ekleyemiyoruz. Peki bu durumda ne yapacagiz. C# 2.0 ile gelen bir ozelligi kullanip, classlara da static anahtar sozcugunu ekleyerek artik istedigimiz islemi yapmis olacagiz.

public static string RemoveNonNumeric(this string str) //this ile o sinifin uyeyisinin ozelligiymis gibi yenilik getirdik.sonuc. diyince cikiyo artik...
{
string res = string.Empty;
foreach (char c in str)
{
if (char.IsNumber(c))
{
res += c;
}
}
return res;
}



3-Collection Initializer: Kullanisli bir C# 3.0 yeniligi daha. Anlatmaya pek gerek kalmayacak, ornegini gosterdigim zaman anlasilacaktir.

List sayilar = new List() { 5, 10 };
ile simdi yazacagim kod arasinda hic bir fark yoktur.

sayilar.Add(5);
sayilar.Add(10);

25 Temmuz 2010 Pazar

C# 3.0 Yenilikleri - I

1-Auto Implemented Property: C# 3.0 yeniliklerinden biridir. Kendilerinin gorevi kisaca sudur ki, eger bir sinif icerisine private bir field yazilip, get ve setlerinde herhangi bir islem yapilmiyorsa, kisaca bizim prop yazip iki kere taba bastigimiz zamanki olusan yapi yazilabilir.

public int Id { get; set; }
public string Ad { get; set; }
public double Fiyat { get; set; }

2-Implicitly Typed Local Variables: Ileriki konularda cok sık kullanacagiz aslinda bu ozelligi. Kisaca ornek uzerinden aciklarsak;

int a=5;
var a=5;

arasinda hic bir fark yoktur. Ide'miz kendisi 5'in int oldugunu anlayip otomatik olarak var a'yi int ozelligine sokuyor.
Kendileri object bir tip olup, mscorlib.dll'i icinde yer alir. Birkac ufak dipnotlar;

1-var e;
var f=null; //bunlar hatali kullanimlardir.
2-Sadece Lokal degiskenlerde kullanilabilirler.
3-Linq'da ve yine c# 3.0 ile gelen anonim tiplerde kullanilirlar.

*** Var, bir tip degildir. Sadece, sag taraftan atanan uyenin tipini anlayip, kendini o tipe donusturen bir "keyword"dur.

3-Anonim Tipler:
Tasarim yapilmis siniflarin nesnelerini olusturmamizi saglayan bir C# 3.0 yeniligidir. Var anahtar sozcugu, arka tarafta olusan sinifin adini temsil etmektedir. Cunku o sinifin adini kod icinde ele alamiyoruz.!

var v=new { Marka = "Renault", Model = "Megane", Hiz = 200 };
Console.WriteLine(v.ToString());//ToString() metodu override ediliyor aslinda.


Anonim Tipler, LINQ sorgulari icinde kullanilir.Bunun idsindaki sinfilari yine bu sekilde yazmaya devam edecegiz.
4-Implicitly Type Arrays: C# 3.0 yeniliklerinden biri de implicitly type arraylerdir. Gelis amaci tamamiyle Anonim tiplerin dizilerini yapmaktir. Kullanimi oldukca basittir, asagidaki ornek yeterince aciklayici olacaktir.

var elemanlar = new[]
{
new{ X=1,Y=2},
new{ X=1,Y=2},
new{ X=1,Y=2}
};

22 Temmuz 2010 Perşembe

C#'da Event Kavrami

Delegelerde de anlattigimiz gibi eventler C# icerisinde buyuk bir oneme sahiptir. Yaptigimiz tum isler aslinda arka planda eventlerin tetiklenmesi sonucu yapilmasi istenilen gorevlerin yapilmasi sonucunda ortaya cikar. Visual Studio sagolsun cogu eventi kendi hazir veriyor, bize sadece yapilmasi istenen goreve gore kod yazmak dusuyor. Simdi biz de kendi eventimizi kendimiz yaratarak bu islemlerin arka planda nasil gerceklestigini inceleyelim.
Senaryomuz basitce soyle olsun. Degiskenleri hic uzatmadan basit bir ornek uzerinden gidiyorum. Stok takip programimiz olsun. Degisken olarak sadece int stok olsun ve stok sayimizi 5er 5er azaltalim. Stok sayisi 10un altina dustugu andan itibaren bize stok azaliyor uyarisini versin. Amacimiz bu. Normalde nasil bir yaklasim uygulanir, if bloklarini yazarsiniz 10dan kucukse sunu yaptir, degilse sunlari yaptir vs. Event tabanli programlamayi kullanarak yapinca daha profesyonel bir yapi olusturmus olacagiz. Aslinda Event'lerin gucunu kavramak icin basit bir ornek bu, daha komplike bir sorunla karsilastigimizda eventlerin gercek gucunu goruruz ama simdilik biz hem hatirlatma maksatli, hem de bilmeyenler icin ogrenme maksatli ufak bir program yazalim.



namespace Event_App_
{
    class Program
    {
        static void Main(string[] args)
        {
            Urun urn = new Urun(50);
            urn.KatDegisti += new Temsilci(urn_KatDegisti);
            for (int i = 0; i < 10; i++)
            {
                urn.StokDurumu();
            }
        }
        static void urn_KatDegisti()
        {
            Console.WriteLine("Stok bitmek uzere...");
        }
    }
    delegate void Temsilci();
    class Urun
    {
        private int stok; 
        public event Temsilci KatDegisti; 
        public int Stok
        {
            get { return stok; }
            set
            {
                stok = value;
                if (value <= 10 && KatDegisti != null)
                    KatDegisti.Invoke();
            }
        }
        public Urun(int stok)
        {
            Stok = stok;
        }
        public void StokDurumu()
        {
            Stok -= 5;
            Console.WriteLine(Stok);
        } 
    }
}

20 Temmuz 2010 Salı

C#'da Delegeler(Delegates)

Method'larimiz calisma aninda RAM'de yer tutarlar, dolayisiyla bir metodun RAM'deki baslangic adresi soz konusudur. Delegeler kisaca, metotlarin bu baslangic adreslerini tutabilen nesnelerdir. Peki biz nerelerde kullanacagiz bunlari. Madde madde siralama yapmadan once kisaca aklima gelen ilk ornegi vereyim. Bir stok takip programiniz var ve stok miktariniz 50nin altina dusunce uyari vermesini istiyorsunuz. Ya da baska gorevler de verdirebilirsiniz. Iste burada delegeleri rahatlikla kullanabiliriz. Yani o metodun calismasi icin(gorev verdigimiz) tetiklenecek bir olay gerekiyor. Iste bunu delegeler yardimiyla yapiyoruz. Aslinda burada farkinda olmadan delegelerin event programlamada kullanildigini belirttik.
Delegelerin Framework icinde yogun kullanildigi yerler;
1-Event tabanli programlama
2-Asenkron programlama
3-LINQ

Simdi kisaca delegelerin nasil tanimlandigini ve baglama islemlerinin nasil yapildigini inceleyelim.
delegate int Temsilci(int a);

Ustteki delege bize, int parametresi alip geriye int donduren bir metodun adresini tutacagini soyler.
Not: Yazdigimiz metodun private ... vs. olmasi onemli degil. Hangi tur erisim belirleyicisine sahip olursa olsun delegelerin tanimlanma bicimi bu sekilde olacak.

Temsilci t = new Temsilci(KareAl);
t += KupAl;
ConsoleWriteLine(t.invoke(5)); // a=5 icin delegelerin cagrilmasi.

Metotlarimiz ise su sekilde;

static int KareAl(int a)
{
return a * a;
}
static int KupAl(int a)
{
return a * a * a;
}

Yukaridaki sonuca gore ciktimiz 25 ve 125 olacaktir. Bir sonraki makalemizde, event tabanli programlamayi anlattigimizda daha da anlasilir olacaktir bu yazdiklarimiz.

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.