|
C#.NET
Bildiğiniz gibi C# dili 2001 yılında Microsoft
tarafından çıkarılan ve nesne yönelimli programlama tekniğine %100
destek veren bir programlama dilidir. C#, programcılara
sunulduğundan beri bir çok programcının dikkatini çekmiştir. Bu
ilgide en önemli neden herhalde C# dilinin kendinden önce çıkarılmış
olan JAVA ve C++ dillerini örnek almasıdır. Evet C# modern çağın
gerektirdiği bütün yazılım bileşenlerini içermekle beraber eski
programlama dillerinde bulunan iyi özellikleri de yapısında
barındırmaktadır. Microsoft ve C# dil tasarımcıları her geçen gün
yeni piyasa araştırmaları yaparak dile katabilecekleri özellikleri
tartışmaktadırlar. Bu amaçla C# dilinin tasarımcıları yakın bir
zaman içinde C# diline eklemeyi düşündükleri yeni özellikleri
bildirmişlerdir. Bu yazıda muhtemelen "VS.NET for Yukon(VS.NET
Everett'ten sonraki versiyon)" ile birlikte uygulamaya konulacak C#
dilinin muhtemel özelliklerini özetlemeye çalışacağım. Bu bildirinin
tamamını C# topluluğunun resmi sitesi olan
www.csharp.net
adresinden okuyabilirsiniz.
C# diline yakın bir zamanda eklenilmesi düşünülen özellikler 4 ana
başlık altında toplanmıştır. Bu özellikler temel olarak aşağıdaki
gibidir.
1 - Generics (Soysal Türler)
2 - Iterators
3 - Anonymous Methods (İsimsiz-Anonim- Metotlar)
4 - Partial Types (Kısmi Türler)
Bu yazıda yukarıda başlıklar halinde verilen her bir konuyu
ayrıntılı olarak inceleyip, programcıya ne gibi faydalar
sağlayabileceğini ve programların performansına nasıl etki edeceğine
değineceğim.
1 - Generics
Profesyonel programlamada, türden bağımsız algoritma geliştirme
önemli bir tekniktir. Türden bağımsız algoritmalar geliştirici için
büyük kolaylıklar sağlamaktadır. Söz gelimi iki int türden sayının
toplanmasının sağlayan bir fonksiyonu yazdıktan sonra aynı işlemi
iki double türden sayı için tekrarlamak zaman kaybına sebep
olacaktır. C++ dilinde türden bağımsız algoritma kurabilmek için
şablon(template) fonksiyonları ve şablon sınıfları kullanılmaktadır.
C#, türden bağımsız algoritma geliştirmeye doğrudan destek vermiyor
olsada dolaylı yollardan türden bağımsız işlemler yapabilmek
mümkündür. Bu işlemler C#'ta "Her şey bir Object'tir" cümlesinin
altında yatan gerçekle halledilmektedir. C#'ta herşeyin bir nesne
olması ve her nesnenin ortak bir atasının olması ve bu atanın da
Object sınıfı olması bu cümlenin altında yatan gerçektir.
Dolayısıyla herhangi bir türe ait referansı Object referasnlarına
ataybiliriz. Yani bir bakıma türden bağımsız bir işlem
gerçekleştirmiş oluyoruz. Söze gelimi Object türünden bir parametre
alan bir fonksiyonu dilediğimiz bir nesne referansı geçebiliriz.
Temel(base) sınıfa ait referanslara türeyen(inherited) sınıf
referanslarını ataybilmek nesne yönelimli programlama tekniğinin
sunduğu bir imkandır.
C#'ta Object referanslarına istenilen türden referanslar atanabilir.
Bu, büyük bir imkan gibi görünsede aslında bazı dezavantajlarıda
beraberinde getiriyor. Çünkü çalışma zamanında Object türüne atanmış
referanslar orjinal türe tekrar geri dönüştürülmektedir. Kısaca
unboxing olarak bilinen bu işlem özellikle değer(value) ve referans(reference)
türleri arasında yapıldığında önemsenecek büyüklükte bir performans
kaybı meydana gelmektedir. Çünkü değer ve referans türleri belleğin
farklı bölgelerinde saklanmaktadır. Bu durum boxing ve unboxing
işlemlerinin çalışma zamanında farklı bellek bölgeleri arasında uzun
sürebilecek veri transferlerine sebep olur. Bu tür bir performans
kaybını bazı veri yapıları için önlemek için C# dil tasarımcıları
Generics isimli bi kavramın dile eklenmesini öngörmüşlerdir. Bu
sayede bazı veri yapılarında özellikle .NET sınıf küyüphanesindeki
System.Collections isim alanında bulunan veri yapılarında epeyce
performans kazancı elde edilecektir.
İsterseniz basit bir yığın(stack) sınıfı üzerinden "generics"
kavramının sağlayacağı yaraları ve boxing/unboxing işlemlerinin
etkisini inceleyelim.
.NET sınıf kütüphanesinde de bulunan Stack sınıfı içinde her türden
veri bulunduran ve istenildiğinde bu verilere LIFO(son giren ilk
çıkar) algoritmasına göre veri çekilebilen bir veri yapısdır. .NET'teki
Stack sınıfı ile bütün veri türlerine ait işlemleri yapabilmek için
Stack sınıfındaki veri yapısı Object olarak seçilmiştir. Eğer bu
böyle olmasaydı Stack sınıfının her bir tür için ayrı ayrı yazılması
gerekecekti. Bu mümkün olsa bile herşey bitmiş olmayacaktı. Çünkü
Stack sınıfı kullanıcını tanımlayacağı türleri barındıracak duruma
gelmez. İşte bütün bu sebeplerden dolayı Stack veri yapısında
saklanan veriler Object olarak seçilmiştir. Buna göre Stack
sınıfının arayüzü aşağıdaki gibidir.
|
class Stack
{
private int current_index;
private object[] elemanlar =
new object[100];
public
void Push(object veri)
{
.
.
elemanlar[current_index] = veri;
.
.
}
public object Pop()
{
.
.
return elemanlar[current_index];
.
.
}
} |
Bildirilen bu Stack sınıfının elemanı Object türünden olduğu için
Push() metodu ile istediğimiz türden veriyi saklayabiliriz. Aynı
şekilde Pop() metodu ile bir veri çekileceği zaman veri Object
türünden olacaktır. Pop() metodu ile elde edilen verinin gerçek türü
belli olmadığı için tür dönüştürme operatörü kullanılır. Örneğin,
şeklinde yığına eklenen veriyi tekrar elde etmek için
biçiminde bir tür dönüşümü yapmamız gerekir. Bu işlemler kendi
tanımlayacağımız özel sınıflar içinde geçerlidir. Ancak int ve
double gibi temel veri türlerindeki performans kaybı daha fazladır.
Çünkü Push(3) şeklindeki bir çağrımda boxing işlemi gerçekleşirken
Pop() metodunun çağrılmasında unboxing işlemi gerçekleşir. Üstelik
bu durumda Pop() metodunun geri dönüş değerini byte türüne
dönüştürmeye çalışırsak derleme zamanında herhangi bir hata almayız.
Bu da çalışma zamanında haberimiz olmadan bazı veri kayıplarının
olabileceğini gösterir. Kullanıcı tanımlı sınıflar ilgili bir yığın
kullanıyorsak Pop() metodunun geri dönüş değerini farklı bir
kullanıcı tanımlı sınıfa çaviriyorsak bu sefer de derleme zamanında
hata alınmaz, ancak çalışma zamanında "invalid cast operation"
istisnai durumu meydana gelir.
Bütün eksi durumlardan kurtulmak için generics(soysal tür)'lerden
faydalanılabilir. Soysal türler C++ dilindeki şablon sınıflarının
bildirimi ile benzerdir. Bu tür sınıf bildirimlerine parametreli
tip de denilmektedir. Parametreli tipler aşağıdaki gibi
bildirilir.
|
class Stack
{
private int current_index;
private Veri türü[]
elemanlar;
public
void Push(Veri türü veri)
{
.
.
elemanlar[current_index] = veri;
.
.
}
public Veri türü Pop()
{
.
.
return elemanlar[current_index];
.
.
}
} |
ile stack sınıfnın hangi türden verileri tutacağı
stack nesnesini oluşturacak programcıya bırakılmıştır. Örneğin int
türden verileri saklayacak bir yığın aşağıdaki gibi oluşturulur.
|
Stack<int> yıgın =
new Stack<int>; |
Yukarıdaki şekilde bir yıgın oluştrulduğunda Stack sınıfınuın
bildirimindeki Veri türü ifadeleri int türü olarak ele
alınacaktır. Dolayısıyla Pop() metodu ile yığından bir eleman
çıkarılıp aşağıdaki gibi başka bir değişkene atanmak istendiğinde
tür dönüştürme operatörünü kullanmaya gerek yoktur. Bu da boxing ve
unboxing işlemlerinin gerçekleşmediği anlamına gelir ki istediğimiz
de buydu zaten.
|
Stack<int> yıgın =
new Stack<int>;
yıgın.Push(3); // Boxing işlemi gerçekleşmez.
int a = yıgın.Pop(); //Unboxing
işlemi gerçekleşmez. |
Aynı şekilde yığınımızın double türden verileri saklamasını
istiyorsak int yerine double kullanmalıyız. Bu durumda çalışma
zamanında hem int hem de double verileri tutan yığın sınıfları
oluşturulacaktır. Biz tek bir yığın sınfı bildirmiş olmamıza rağmen
çalışma zamanı bizim için ayrı iki yığın sınıfı oluşturur.
Soysal türleri kendi tanımladığımız sınıflar içinde oluşturabiliriz.
Örneğin Musteri isimli bir sınıfın verilerini yığında tutmak için
yığın sınıfını aşağıdaki gibi oluşturmalıyız.
Bu durumda yığına sadece Musteri nesneleri eklenebilir. Yani yıgın.Push(3)
şeklindeki bir kullanım derleme aşamasında hata verecektir. Aynı
zamanda yığından çekilecek veriler de Musteri türündendir.
Dolayısıyla tür dönüşümü uygun türler arasında olmalıdır.
Yığın sınıfı yukarıda anlatılan şekilde kullanıldığında yığındaki
elemanların belirli bir türden olduğu garanti altına alınır. Böylece
Musteri türünden nesneleri tutan bir yığına "3" gibi bir sayıyı
ekleyemeyeceğimiz için daha gerçekçi programlar yazılır.
Stack örneğinde sadece bri tane parametre türü kullandık. Soysal
türlerde istenilen sayıda parametreli tür kullanılabilir. Örneğin
Hashtable sınıfnındaki Deger ve Anahtar ikilisi aşağıdaki gibi
parametreli tür olarak bildirilebilir.
|
public class
Hashtable
{
public void Add(AnahtarTuru
anahtar, DegerTuru deger)
{
.....
}
public DegerTuru
this[AnahtarTuru anahtar]
{
.....
}
}
|
Yani bir Hashtable nesnesi oluşturulacağı zaman her
iki parametre türü de belirtilmelidir. Örneğin Anahtar türü int olan
ve değer türü Musteri sınıfı olan bir Hashtable nesnesi aşağıdaki
gibi oluşturulabilir.
|
Hashtable<int,Musteri>
hashtable = new Hashtable<int,Musteri>; |
Not : Parametre sayısını aralarına virgül koyarak
dilediğimiz kadar artırabiliriz.
Soysal türlerin saydığımız avantajlarının yanında bu haliyle bazı
dezavantajları ve kısıtlamalarıda vardır. Söz gelimi Hashtable
sınıfının bildirimi içinde AnahtarTuru verisinin bazı elemanlarını
bir ifade de kullanmak istiyoruz; derleyici hangi AnahtarTuru
parametrelei türünün hangi türden olduğunu bilmediği için bu durumda
sadece Object sınıfının ait metotlar ve özellikler kullanılabilir.
Mesela Hashtable sınıfının Add metodu içinde anahtar parametresi ile
CompareTo() metodunu kullanmak istiyorsak CompareTo metodunun
bildirildiği IComparable arayüzünü kullanarak aşağıdaki gibi tür
dönüşümü yapmalıyız.
|
public class
Hashtable
{
public void Add(AnahtarTuru
anahtar, DegerTuru deger)
{
switch(((IComparable)anahtar).CompareTo(x))
{
}
}
}
|
Hashtable sınıfının Add() metodu yularıdaki şekilde
bildirilse bile hala eksik noktalar var. Mesela AnahtarTuru
parametresi eğer gerçekten IComparable arayüzünü uygulamıyorsa
switch ifadesi içinde yapılan tür dönüşümü geçersiz olacaktır ve
çalışma zamanında hata oluşacaktır. Çalışma zamanında meydana
gelebilecek bu tür hataları önlemek için yapılabilecek tek şey
AnahtarTuuru parametresinin IComparable arayüzünü uyguluyor olmasını
zorlamaktır. Bu işlemi yapmak için AnahtarTuru parametresine çeşitli
kısıtlar(constraints) getirilir. Aşağıdaki Hashtable
sınıfında AnahtarTuru parametresinin IComparable arayüzünü
uygulaması gerektiği söylenmektedir. Bu kısıt için where
anahtar sözcüğü kullanılır.
|
public class
Hashtable<AnahtarTuru, DegerTuru>
where AnahtarTuru : IComparable
{
public void Add(AnahtarTuru
anahtar, DegerTuru deger)
{
switch(anahtar.CompareTo(x))
{
}
}
} |
Dikkat ettiyseniz uygulanan kısıttan sonra switch
ifadesi içinde anahtar değişkeni üzerinde tür dönüşümü işlemi
yapmaya gerek kalmamıştır. Üstelik kaynak kodun herhangi bir
noktasında Hashtable nesnesini IComparable arayüzünü uygulamayan bir
AnahtarTuru parametresi ile oluşturursak bu sefer ki hata derleme
zamanında oluşacaktır.
Not : parametreli türler üzerindeki kısıt sadece arayüz olmak
zorunda değildir. Arayüz yerine sınıflar da kısıt olarak
kullanılabilir.
Bir parametreli türe birden fazla arayüz kısıtı konabileceği gibi
aynı sınıftaki diğer parametreleri türler için de kısıt konulabilir.
Ancak bir parametreli tür için ancak sadece bir tane sınıf kısıt
olabilir. Örneğin aşağıdaki Hashtable sınıfında DegerTuru Musteri
sınıfından tremiş olması gerekirken, AnahtarTuru hem IComparable
hemde IEnumerable arayüzünü uygulamış olması gerekir.
|
public class
Hashtable<AnahtarTuru, DegerTuru>
where
AnahtarTuru : IComparable
AnahtarTuru : IEnumerable
DegerTuru : Musteri
{
public void Add(AnahtarTuru
anahtar, DegerTuru deger)
{
switch(anahtar.CompareTo(x))
{
}
}
} |
2 - Iterators
Bir dizinin elemanları üzerinde tek tek dolaşma
işlemine iterasyon denilmektedir. Koleksiyon tabanlı nesnelerin
elemanları arasında tek yönlü dolaşmayı sağlayan foreach döngü
yapısının bizim tanımlayacağımız sınıflar için de kullanılabilmesi
için sınıfımızın bazı arayüzleri uyguluyor olması gerekir. foreach
döngüsü derleme işlemi sırasında while döngüsüne dönüştürülür. Bu
dönüştürme işlemi için IEnumerator arayüzündeki metotlardan ve
özelliklerden faydalanılmaktadır. Bu dönüştürme işleminin nasıl
yapıldığına bakacak olursak :
|
ArrayList alist = new ArrayList();
foreach(object
o in alist)
{
BiseylerYap(o);
}
// Yukarıdaki foreach bloğunun karşılığı aşağıdaki gibidir.
Enumerator e = alist.GetEnumerator();
while(e.MoveNext())
{
object o = e.Current
BiseylerYap(o);
} |
foreach döngüs yapısı için gerekli olan arayüzlerin
uygulanması özellikle ağaç yapısı şeklindeki veri türleri için
oldukça zordur. Bu yüzden C# sınıfların foreach yapısı ile nasıl
kullanılacağına karar vermek için yeni bir yapı kullanacaktır.
Sınıflarda, foreach anahtar kelimesi bir metot ismi gibi
kullanılarak sınıfın foreach döngüsünde nasıl davranacağını
bildirebilriz. Her bir iterasyon sonucu geri döndürülecek değeri ise
yield anahtar sözcüğü ile belirtilir. Örneğin her bir
iterasyonda farklı bir tamsayı değeri elde etmek için sınıf
bildirimi aşağıdaki gibi yapılabilir.
|
public class
Sınıf
{
public int foreach()
{
yield 3;
yield 4;
yield 5;
}
} |
Yukarıda bildirilen Sınıf türünden nesneler üzerinde
foreach döngüsü kullanıldığında iterasyonlarda sırasıyla 3,4 ve 5
sayıları elde edilecektir. Buna göre aşağıdaki kod parçası ekrana
345 yazacaktır.
|
Sınıf deneme = new Sınıf();
foreach(int
eleman in deneme)
{
Console.Write(eleman);
} |
Çoğu durumda foreach yapısı ile sınıfımızın içindeki
bir dizi üzerinde iteratif bir şekilde dolaşmak isteyeceğiz. Bu
durumda foreach bildirimi içinde ayrı bir foreach döngüsü aşağıdaki
gibi kullanılabilir.
|
public class
Sınıf
{
private int[] elemanlar;
public int foreach()
{
foreach(int
eleman in elemanlar)
{
yield
eleman;
}
}
} |
Yukarıdaki Sınıf nesneler ile foreach döngüsü kullanıldığında her
bir iterasyonda elemanlar dizisinin bir sonraki elemanına ulaşılır.
Gördüğünüz gibi programcının bildireceği sınıflar da
foreach döngüs yapısını kullanabilmek için eskiden olduğu gibi
IEnumerator arayüzün uygulamaya gerek kalmamıştır. Bu işlemi
derleyici bizim yerimize yapar.
3 - Anonymous Metotlar(İsimsiz Metotlar)
İsimsiz metotlar, bir temsilciye ilişkin kod
bloklarını emsil eder. Bildiğiniz gibi temsilciler yapısında metot
referasnı tutan veri yapılarıdır. Bir temsilci çağrımı yapıldığında
temsilcinin temsil ettiği metot çalıştırılır. Özellikle görsel
arayüzlü programlar yazarken event tabanlı programlama tekniği
kullanılırken temsilcilerin kullanımına sıkça rastlanır. Örneğin bir
Button nesnesine tıklandığında belirli bir kod kümesinin(metot)
çalıştırılması için temsilci veri yapısından faydalanılır. Sözgelimi
Button nesnesinin tıklanma olayı meydana geldiğinde Click isimli
temsilcisine yeni bir temsilci atanır. Ne zaman button nesnesinin
Click olayı gerçekleşse ardından hemen temsilcinin temsil ettiği
metot çağrılır. Buna bir örnek verecek olursak;
|
public class
Form
{
Button dugme;
public Form
{
dugme =
new Button();
dugme.Click += new
EventHandler(OnClick);
}
void OnClick(object
sender, EventArgs e)
{
....
}
} |
Yukarıdaki koddan da görüldüğü üzere temsilci ile
temsilcinin temsil ettiği metotlar ayrı yerlerdedir. İsimsiz
metotlarla bu işlemi biraz daha basitleştirmek mümkündür. Temsilci
oluşturulduktan sonra açılan ve kapanan parantezler arasına temsilci
çağrıldığında çalıştırılacak kodlar yazılabilir. Yukarıdaki örneği
isimsiz metot ile yapacak olursak :
|
public class
Form
{
Button dugme;
public Form
{
dugme =
new Button();
dugme.Click += new
EventHandler(object sender,
EventArgs e);
{
//çalıştırılacak kodlar.
};
}
} |
Tanımlanan kod bloğundan sonra noktalı vürgülün eklenmiş olduğuna
dikkat edin. Temsilci bloğundaki kodlar normal metotlardan biraz
farklıdır. Normal kod blokları ile benzer özellikler taşır.
Yukarıdaki temsilci kod bloğunda, blok dışında tanımlanan
değişkenlere erişebilmek mümkündür. Ayrıca olay argümanlarının da(sender,e)
EventHandler türünün parantezleri içinde yazıldığınıda dikkat edin.
Bir önceki versiyonda olay argümanlarının yerine temsil edilen
metodun ismi yazılmıştı.
Peki isimsiz metotlar nasıl çalıştırılmaktadır? İsimsiz metot tanımı
ile karşılaşan derleyici tekil isme sahip bir sınıf içinde tekil
isme sahip bir metot oluşturur ve isimsiz metot gövdesindeki kodlara
bu tekil metot içinden erişilir. Temsilci nesnesi çağrıldığında,
derleyicinin ürettiği bu metot ile isimsiz metodun bloğundaki kodlar
çalıştırılır.
4 - Partial Types (Kısmi Türler)
Kısmi türler yardımıyla bir sınıfın elemanlarını farklı dosyalarda
saklamak mümkündür. Örneğin Dosya1.cs ve Dosya2.cs aşağıdaki gibi
olsun.
|
//Dosya1.cs
public partial class
deneme
{
public void Metot1
{
...
}
} |
|
//Dosya2.cs
public partial class
deneme
{
public void Metot2
{
...
}
} |
Yukarıdaki iki dosyayı aynı anda derlediğimizde eğer kısmi türler
kavramı olmasaydı derleme zamanında hata alırdırk. Çünkü aynı isim
alanında birden fazla aynı isimli sınıf bildirimi yapılmış. Halbuki
kısmi türler ile bu iki sınıf bildirimi aynı sınıf olarak ele
alınır, ve birleştirilir. Yani deneme isimli sınıfın Metot1() ve
Metot2() adında iki tane metodu olmuş olur.
Bir türe ait elemanları tek bir dosya içinde toplamak Nesne
Yönelimli Programlama açısından her ne kadar önemli olsada bazen
farklı dosyalarla çalışmak kodlarımızın yönetilebilirliğini
artırabilmektedir.
Not : Bu yazı "MSDN Magazine" deki "Future
Features of C#" başlıkla bildiri baz alınarak hazırlanmıştır.
Bu günlerde hepimiz .Net Framework
3.0 ve getirileri üzerine yoğunlaşmış durumdayız. Özellikle mimari
anlamda yapılan köklü değişimler söz konusu. Bu köklü değişiklikler;
Windows uygulamalarının yeni yüzü olan WPF (Windows Presentation
Foundation) ve XAML (eXtensible Application Markup Language),
dağıtık mimariyi tek çatı altında toplamayı başaran WCF (Windows
Communication Foundation), akış şemaları ve iş süreçlerinin .Net
plaformuna dahil edilmesini sağlayan WF(Workflow Foundation) ve
CardSpace olarak sıralanabilir. Ancak bunların dışında Microsoft’ un
gelecek vizyonu içerisinde yer alan en önemli konulardan biriside C#
3.0 konusudur. Bildiğiniz gibi C#, sıfırdan geliştirilmiş ve atası
olan nesne yönelimli dillerin en iyi özelliklerini bünyesinde
birleştirerek bunu güçlü bir Framework üzerinde kullanabilmemizi
sağlayan bir dildir. Zaman içerisinde C# 2.0 ile gelen yenilikler şu
anda tüm C# geliştiricilerin hayatının bir parçası haline gelmiştir.
Şimdi herkesin gözü C# 3.0 üzerinde.
C# 3.0, beraberinde LINQ (Language
Integrated Query),
DLINQ
(Database Language Integrated Query) ve
XLINQ
(Xml Language Integrated Query) gibi yeni teknolojileride getirmekte
ve desteklemektedir. Biz bu makalemizde daha fazla LINQ ifadesi
yazmaya çalışacağız. Onbir basit LINQ ifadesi ile dil tabanlı
sorguları daha yakından tanımaya başlıyacak ve elimizdeki gücün
farkına varacağız. Bildiğiniz gibi LINQ (Language Integrated Query)
özellikle dil içerisinde, Sql tarzı sorgular yazabilmemizi ve
bunları var olan IEnumerable<T> türevli tipler üzerinde
kullanabilmemizi sağlamaktadır. Ancak özellikle LINQ içerisinde
kullanılabilen operatörler göz önüne alındığında, oldukça etkili
sonuçlar alabileceğimiz ortadır. Temel olarak LINQ içerisindeki
operatörler aşağıdaki başlıklar altında toplanmıştır. (Elbetteki
bu bilgiler hala deneme aşamasında olan bir sürece aittir ve
değişebilir.)
- Kısıtlama Operatörleri (Restriction
Operators) -> Where
- Gruplama Operatörleri (Grouping
Operators) -> Group
- Sıralama Operatörleri (Ordering
Operators) -> OrderBy, ThenBy, Reverse
- Bölümleme Operatörleri (Partitioning
Operators) -> Take, Skip, TakeWhile, SkipWhile
- Seçme Operatörleri (Projection
Operators) -> Select
- Set Operatörleri (Set Operators)
-> Distinct, Union, Intersect, Except
- Dönüştürme Operatörleri (Conversion
Operators) -> ToArray, ToList, ToDictionary, OfType
- Eleman Operatörleri (Element
Operators) -> First, FirstOrDefault, ElementAt
- Üretim Operatörleri (Generation
Operators) -> Range, Repeat
- Gruplama Fonksiyonu Operatörleri
(Aggregate Operators) -> Count, Sum, Min, Max, Averaga, Fold
- Ölçüm Operatörleri (Quantifiers
Operators) -> Any, All
- Çeşitli Operatöler (Miscellaneous
Operators) -> Concat, EqualAll
- Özel Seri Operatörleri (Custom
Sequence Operators) -> Combine
Şimdi gelin bu operatörlerin bir
kısmını incelemeye çalışalım. Öncesinde program ortamında ele
alabileceğimiz bazı veri kümelerine ihtiyacımız olacak. Bu veri
kümeleri tamamıyla test amaçlı olacaktır. Bunun için AdventureWorks
veritabanında yer alan Product ve ProductSubCategory tablolarından
faydalanabiliriz. Amacımız ilk olarak buradaki tablolardan test
amacıyla kullanabileceğimiz veri kümelerini program ortamı
içerisinde yer alan generic koleksiyonlara aktarmaktır. LINQ konusu
söz konusu olduğu içinde, C# 3.0 dili özelliklerinden de
faydalanmaya çalışacağız.
Yardımcı sınıfımızın kodları
aşağıdaki gibidir.



|