You are on page 1of 10

C# 3.

0 : Dil Yenilikleri ve LINQ (Language Integrated Query)


Bu iki makaleden oluşan dizide sizlere C# 3,0 ın biz programcılara ne gibi yenilikler getirmeye çalıştığından
bahsedeceğim. Makaleme başlamadan önce hepinizin kafasında oluşabilecek muhtemel sorulara cevap vermek
istiyorum. Henüz daha C# 2.0 a alışmadan ve C# 2.0 ın getirdiği yenilikleri hazmetmeden C# 3.0 dan bahsediyor
olmak aslında Microsoft un C# diline ne kadar önem verdiğini göstermektedir. Programcıların sıkça kullandığı
yapılardan ve günümüzde yoğun kullanılan programatik deyimlerden yola çıkarak kod yazmayı ve üretkenliği
artıracak yeni dil eklentilerinin C# a eklenmesi kimileri tarafından olumsuz bir şekilde eleştirilsede ben olumlu
karşılıyorum. C# dili genel amaçlı bir programlama dili olmasına rağmen günümüzdeki kullanım alanı ile ilgili yapılan
araştırmalara göre büyük bir kesimin C# dilini veri merkezli (data centric) uygulamaları tasarlamak için kullandığı
görülmüştür. Yani hemen hemen her C# uygulamasında bir veri kaynağı bulunmakta ve bu veriler anlamlı hale
getirilerek işlenmekte. Hatta yakın bir zamanda şahit olduğum bir olayı anlatmak istiyorum. 2005 yılında Amerika da
C# dilinin mimarlarından olan Anders Hejlsberg in bir sunumuna katılmıştım. Sunum tabiki C# 3.0 ile ilgiliydi.
Hejlsberg katılımcılara "Kaç kişi geliştirdiği herhangi bir uygulamasında herhangi bir veritabanı kullandı?"
sorusunu yöneltti. Katılımcılara soru anlamsız! geldiğinden olsa gerek önce soru anlaşılmadı. Hejslberg soruyu
tekrarlayınca herkesin eli havadaydı. Hejslberg, işte bu yüzden C# 3.0 a birazdan anlatacağım yenilikleri ekledik
dedi ve sunumuna devam etti. İstatistikler ve gerçekler gösteriyorki .NET paltfomu daha çok veri merkezli
uygulamalarda kullanılıyor. Bu yüzden .NET platformunun yaygın kullanılan bu amacına yönelik olarak .NET
dillerininde üretkenliklerini artıracak yeni özelliklerin eklenmesi kaçınılmaz hale gelmiştir.

Günümüzde en çok veri kaynağı olarak veritabanı sistemleri kullanılmaktadır. Genel amaçlı bir programlama dilinden
(mesela C#, VB.NET, C++ ) beklediklerimiz ile veritabanı sistemlerinden beklediklerimiz arasında tam bir uyumdan
bahsetmek mümkün değildir. Söz gelimi C# ve SQL Server dan bir örnek vermek gerekirse, C# dilinde int türünden
bir veri değişkeni null değer içeremezken aynı veri tipinin SQL Server daki karşılığı olan tip null değer
içerebilmektedir. Bu yüzden genel amaçlı bir programlama dili ile özel amaçlı bir geliştirme yapmanın ekstra efor
gerektirdiğini söylemek sanırım yanlış olmayacaktır. Bu tür durumları gidermek için programlama diline yapılan
eklentiler o dilin zamanla genel amaçlı dil olmasından çıkarabileceği için yeni eklenen özelliklerin dikkatle ve özenle
seçilmesi gerekiyor. Bu amaçla C# 2.0 da null değer alabilen temel değer tipleri kavramı eklenmiştir. Bu özellik aynı
zamanda generics altyapısı ile desteklendiği için dilin genel amaçlı olma özelliği kaybolmamıştır.

C# 3.0 a eklenmesi öngörülen yeni özelliklerinde yine bu amaca yönelik olduğu açıkca gözükmektedir. Yani
birazdan detaylı olarak ele alacağım C# 3.0 yeniliklerinin hemen hemen tamamı veri merkezli uygulamaların daha
hızlı geliştirlmesi için gereken yapıları desteklemek amacıyla eklenmiştir. Bu yüzden C# diline yeni eklenecek olan
özellikleri öncelikli olarak geliştirilme amaçlarına yönelik irdeleyeceğiz.

C# 3.0 ve LINQ (Language Untegrated Query) nedir?

C# 3.0 ilk olarak 2005 yılındaki PDC (Professional Developer Conference) etkinliğinde duyruldu. C# 3.0 daki yeni
özellikler ilk olarak LINQ (Language Integrated Query) adı verilen bir proje ile anılmaya başlandı. LINQ projesi C#
diline entegre olmuş hafızadaki veya harici bir kaynaktaki verileri hızlı ve efektif bir şekilde sorgulayabilecek yapılara
verilen bir takma isimdir. C# 3.0 daki yeniliklerin şimdilik tamamı LINQ projesinin altyapısını oluşturmaktadır. Bu
makalede sizlere C# 3.0 daki dil yeniliklerinden ve sonrasında ise LINQ projesinin kapsamından bahsedeceğim.

C# 3.0 ın yeniliklerini kısıtlı da olsa derleyebilen bir derleyici PDC de yayınlanmıştı. Bu derleyici VS.NET 2005 ile
entegre çalışabilmektedir. PDC olduğu sıralarda Visual Studio.NET 2005 beta aşamasında olduğundan daha sonra
final sürümü için başka bir kurulum hazırladılar. LINQ Preview olarak adlandırılan bu kurulum derleyiciyi ve VS.NET
eklentilerini barındırıyor. İndirmek için aşağıdaki bağlantıya tıklayabilirsiniz.

Visual Studio.NET 2005 Final Sürümü için LINQ Preview kurulum dosyaları

Kurulumu yaptıktan sonra Visual Studio.NET 2005 editöründe aşağıdaki gibi bir eklentinin yapıldığını göreceksiniz.
Bu proje tiplerinden birini seçtiğinizde LINQ için gerekli olan kütüphaneler otomatik olarak referans edilecek ve "Build"
işlemini gerçekleştirdiğinizde C# 3.0 derleyicisi otomatik olarak çalıştırılacaktır.
LINQ yapıları ve C# 3.0 daki dil yeniliklerinin son hali kod adı "Orcas" olan ve şu anda çıkma tarihi kesin belli
olmayan (tahminen 2007 nin sonu yada 2008 in başı )Visual Studio.NET versiyonu ile belirlenecektir. Dolayısıyla
birazdan detaylı olarak ele alacğım C# 3.0 dil yeniliklerinin 2 sene içerisinde çok fazla değişime uğrayacağını
söyleyebiliriz. Nitekim şu anda yayımlanan versiyon, Anders Hejlsberg in de dediği gibi bir nabız yoklamadır.

En çok merak edilen konulardan bir tanesi de C Omega ile C# 3.0 ın aralarındaki ilişki. Öncelikle C Omega nın
Microsoft Research bünyesinde gerçekleştirilen bir araştırma projesi olduğunu söylemek gerekir. Dolayısıyla C
Omega ile C# 3.0 arasında direkt bir ilişkiden bahsetmek mümkün değildir. Her iki ekipte birbirlerinden tamamen
bağımsız çalışmaktadır. C Omega ekibi deneme yanılma yolu ile yenilikler üreterek C# dilini geliştiren ekibe yardımcı
olmakta. Kısacası C Omega dili tamamen ayrı bir uzayda değerlendirilmelidir. C Omega nın Microsoft un
herhangi bir ürününde yer alması yada ayrıca pazarlanması düşünülmemektedir.

C Omega hakkında detaylı bilgi almak için tıklayınız.

C# 3.0 Dil Yenilikleri

Bu bölümde C# 3.0 a eklenmiş olan yeniliklerden detaylı bir şekilde bahsedeceğim. Bolum sonunda daha detaylı
bilgi için çeşitli bağlantılar da vereceğim. Yukarıda da söylediğim gibi dile eklenen özelliklerin tamamı LINQ yapılarını
desteklemek amıcıyla eklenmiştir. Ve elbetteki bir çok özellik C# 2.0 daki yeniliklerin üzerine inşa edilmiştir. Burada
bahsedeceğim bir çok yeniliği anlayabilmeniz için C# 2.0 daki yenilikleri biliyor olmanız gerekir. C#nedir?com da C#
2.0 ile ilgili yayınlanmış bir çok makale var. Öncelikle onları okumanızı tavsiye ediyorum.

1 - Bilinçsizce türlendirilmiş yerel değişken tanımlama (Implicitly typed local variables)

Birgün mutlaka olmasını istediğim bir özellikti bu. İlk duyduğumda çok sevinmiştim. C# 3.0 da değişkenleri
tanımlarkan artık tiplerini vermek zorunda değiliz. Dile eklenen "var" isimli bir anahtar sözcükle değişkenleri
tanımlamak mümkün hale gelmiştir. Değişkenin tipinin ne olacağına o değişkene atanan ilk değer ile karar
verilmektedir. Örneğin aşağıdaki kullanımlar tamamen geçerli olmaktadır.

var a = 5;
var b = true;
var s = "sefer algan";
var p = new Personel(); //Personel sınıfımızın oldugunu varsayıyorum.

İlk akla gelen soru bu tanımlama şeklinden performansın ne şekilde etkileneceği? Cevabı çok basit: değişen hiç
birşey yok. Çünkü bu kullanım javascript te bulunan var yada eski VB 6 da bulunan var(variable) tanımlama
biçimlerinden tamamen farklıdır. Derleyici var ile bildirilen değişkenlere atanan ilk değerlere bakarak değişkenin tipine
karar verir ve ürettiği kodu ona göre belirler. Yani yukarıdaki kod blokları ile aşağıdaki kod bloklarının IL seviyesinde
hiç bir farklılığı yoktur. Dolayısıyla bu değişiklik performansı hiç bir şekilde etkilemeyecektir.

int a = 5;
bool b = true;
string s = "sefer algan";
Personel p = new Personel(); //Personel sınıfımızın oldugunu varsayıyorum.

var ile object tanımlamayı karıştırmamak gerekir. object bir referans tipidir ve bellekte belirli bir yer kaplar. Kendisine
atanan değişkenler değer tipleri ise boxing ve unboxing işlemi gerçekleşir ki bu da performans düşmesine neden olur.
Ancak var bir veri tipi değildir sadece bir değişken bildirme biçimidir.

var bildirim şekli daha sonra bahsedeceğim isimsiz tipleri(anonymous types) desteklemek amacıyla dile
eklenmiştir.

var ile bildirilen değişkenlerin tipleri derleme zamanında belirlendiği için aşağıdaki kullanım tamamen geçersizdir.
Aşağıdaki geçersiz kullanım var ve object arasındaki farklı sanırım açıklayacaktır.

var a = 7;
a= "s"; // geçersiz atama cunku a derleyici tarafından int olarak belirlendi.

//Diğer hatalı durumlar


var a; // ilk değer verilmek zorunda
var b = null; // tip belli olmadığından null değer alamaz

var deyiminin bir kullanım alanıda karışık ve yazılması zor olan veri tiplerini kısa bir şekilde tanımlamak. Örneğin
aşağıdaki gibi generic bir hashtable koleksiyonu tanımlanabilir.

Dictionary<Personel, List<int>> puanlar = new Dictionary<Personel, List<int>>;

// yerine

var puanlar = new Dictionary<Personel, List<int>>;

2 - Nesnelere ve koleksiyonlara ilk değer ataması (Object and Collection Initializers) Nesneleri yaratırken yapıcı
metotlar yardımıyla nesnelerin özelliklerini belirleriz. Farklı amaçlarla çeşitli şekillerde aşırı yüklenmiş yapıcı metotlar
yazmak zorunda kalıyoruz çoğu zaman. C# 3.0 a eklenen bir yapı ile birlikte artık işlevi sadece özelliklerini atamak
olan yapıcı metotlar yazmamıza gerek kalmayacak. Çünkü nesneyi yada koleksiyonu tanımladığımız anda
nesnesinin özelliklerini verebiliyoruz. Buna göre aşağıdaki kullanım artık tamamen geçerlidir.
public class Personel
{
public int No;
public string Ad;
public Maas maas;
}

public class Maas


{
public int Tutar;
public string Kur;
}

static void Main()


{
var alininMaasi = new Maas{Tutar=1000, Kur ="USD"};

var ali = new Personel{No=12, Ad="Ali Aslan",maas = alininMaasi }

//yada

Personel veli = new Personel{No=12, Ad="Veli Aslan",maas = new Maas{Tutar=200,Kur="YTL"} }


}

Nesnelere ilk atama yapmak dışında bu yapı kullılarak koleksiyonlarada başlangıç değerleri verilebilmektedir. Bunun
için koleksiyonun mutlaka System.Collections.Generic isim alanında bulunan ICollection<T> arayüzünü uygulaması
gerekmektedir. AŞağıdaki gibi bir tanımlama yapıldığı anda ICollaction<T>.Add(T eleman) isimli metot her bir eleman
için otomatik olarak çağrılmaktadır.

List<string> isimler = new List<string> {"ali","veli","sefer","oguz","burak","mustafa"};

3 - İsimsiz Veri Tipleri (Anonymous Types)

C# 2.0 da isimsiz metotlar yeniliği vardı hatırlarsanız. Şu anda ise isimsiz veri tipleri ile karşı karşıyayız. Öyle bir veri
tipi düşünün ki adı yok. Peki adı yoksa bu veri tipini nasıl oluşturacağız ve bu tipten bir nesne nasıl yaratacağız.
Cevabını tahmin ediyor olmanız lazım: elbette ki var deyimi ile. Bir değişkenin hangi veri tipi modelinde olacağı artık
değişkenin tanımlandığı noktada yapılabilmektedir. Ancak değişkenin tipi belli olmadığı için mecburen var ile
tanımlamak zorundayız. Bu yapıyı JavaScript dilini bilinler anımsayacaktır. Buna göre 3 elemandan oluşan bir
Personel veri yapısı aşağıdaki gibi basitçe tanımlanabilmektedir.

var veli = new {No=12, Ad="Veli Aslan"}

Console.WriteLine( veli.No.ToString());
Console.WriteLine( veli.Ad);

var ali = new {No=3, Ad="Ali Aslan"}

ali = veli // bu atama geçerlidir cunku isimsiz tipler aslında IL de aynı tipe denk düşer.

var veli2 = new {ali.No,ali.Ad}; // şeklinde de tanımlama yapılabilir. Boylece veli değişkeni otomatik olarak ali değişlenin
tipinde olacaktır.

Yukarıdaki gibi isimsiz tip tanımlaması yapıldığında C# derleyicisi otomatik olarak bir int birde string property ve field
içeren bir sınıf yaratıp IL kodunun içine gömecektir. Böylece ismini bilmesekte kullanabildiğimiz bir veri yapısı
olacaktır.

4 - Genişletme Metotları (Extension Methods)


Genişletme metotları derlenmiş yada kod içerisinde bulunan herhangi bir veri tipini yeni metotlarla genişletme
amacıyla eklenmiştir. Örneğin kendimiz bir genişletme metotdu yazarak string sınıfına yeni bir metot tanımlayabiliriz.
Hatta object metoduna yeni bir extension metot bile yazabiliriz. Boylece her türlü nesnede bizim yazdığımız metot
otomatik olarak görülecektir. Genişletme metotlatrınında yine LINQ kapsamındaki sorgu ifadelerini desteklemek
amacıyla yapıldığını birazdan göreceksiniz. Ancak her ne kadar LINQ için konulmuş bir özellik olsada yapı esnek
tutulmuş ve herhangi bir tip için genişletme metodu tanımlayabileceğimiz halde tasarlanmıştır.

Söz gelimi string sınıfı için ToInt32 adı ile yeni bir metot tanımlayabiliriz. Boylece string değişkenlerini tam sayıya
dönüştürmek için Convert.ToInt32 metodunu kullanmamıza gerek kalmayacak. Yada kendi ihtiyaçlarınıza özel olarak
string sınıfına farklı farklı metotlar ekleyebilirsiniz.

Genişletme metotları ile ilgili bilmemiz gereken en önemli kural metodun mutlaka statik bir sınıf içerisinde statik olarak
tanımlanması gerektiğidir. (Statik sınıflar C# 2.0 a eklenen yeni bir özelliktir). Statik sınıflarla ilgili Burak Selim
Şenyurt un detaylı bir makalesini sitemizden bulabilirsiniz.) Genişletme metotlarının ilk parametresi hangi veri tipi ile
ilgili ise this anahtar sözcüğü ile belirtimelidir. Aşağıda ornek bir genişletme metodu görmektesiniz.

namespace ExtensionMethods
{
public static class MyExtensions
{
public static int ToInt32(this string str)
{
return Int32.Parse(str);
}
}
}

Yukarıdaki sınıf bildiriminden sonra using ExtensionMethods; denilen her yerde kullanılan string tipindeki
değişkenlerde ToInt32 isimli metot yer alacaktır. Gördüğünüz gibi string sınıfında gerçekte olmayan bir metot varmış
gibi davranıyor derleyici. Bu bildirimlerden sonra aşağıdaki kod tamamen geçerli olacaktır.

using ExtensionMethods;
class Program
{
public static void Main
{
string str = "35";
int a = str.ToInt32();
}
}

Genişletme metotlarının bildiriminde bulunan ve this öneki alan parametre genişletmek istediğimiz tipi ve metoda
gönderilecek olan parametre değişkeninmi temsil etmektedir. Dolayısıyla yukarıdaki örnekte görüldüğü üzere str isimli
değişken sanki metodun parametresiymiş gibi davranıyor. Birden fazla parametresi olan genişletme metotlarıda
tanımlamak mümkündür. İlk parametre dışındakileri normal bildiğimiz şekilde tanımlanmaktadır. Örneğin string
sınıfının Substring metodunun sondan başlayacak şekilde düzenleyip adını EndSubstring() şeklinde bildirebiliriz.
Örneğin str.EndSubstring(4); dediğimizde sondan itibaren 4 karakterlik alt bolumu geri donecektir. Böyle bir metot
aşağıdaki gibi tanımlanabilir.

namespace ExtensionMethods
{
public static class MyExtensions
{
public static string EndSubstring(this string str,int count)
{
return str.Substring(str.Length- count, 4);
}
}
}

Genişletme metotlarının metot aşırı yükleme ve yansıma(reflection) gibi konularda nasıl davranacağı ile ilgili henüz
net bir bilgi bulunmamaktadır. Bütün bunların cevabını ilerleyen zamanlarda öğreneceğiz.

Önemle vurgulanması gereken konu genişletme metotları kalıtım yolu ile türetmeye bir alternatif olarak gelmemiştir.
Buradaki amaç tamamen LINQ projesini desteklemek olduğu için klasik türetme mantığını korumamızda fayda var.
Genişletme metotları gibi ileriki zamanlarda genişletme özellikleri, olayları ve operator metotlarınında olacağı
söylenmekte. Ancak şu andaki derleyici bu tür yapıları desteklememektedir.

5 - Lambda İfadeleri (Lambda Expressions)

Lambda ifadeleri Pyhton, Lisp ve Schema gibi bir çok programlama dilinde öteden beri olan yapılardır. Güçlü yapısı
sayesinde çok karışık algoritmaları kolay bir şekilde ifade edebilmemize yarıyor. Bir dilde olmazsa olmaz yapılardan
olmasada programcıya büyük kolaylık sağlamaktadır. Lambda ifadelerini aynı örneğin C# 1.1, C# 2.0 ve C# 3.0
versiyonlarını yaparak daha rahat anlayabiliriz. Örneğimizi C# 2.0 ile birlikte gelen List<T> generic sınıfından yola
çıkarak yapacağız. C# 1.1 de Generic sınıflar yer almadığından C# 1.1 için vereceğim örnek elbetteki 1.1 derleyicisi
ile derlenemeyecektir. C# 1.1 örneğini yine C# 2.0 ile derleyeceğiz ama C# 2.0 daki isimsiz metotların(anonymous
method) olmadığını varsayacağız.

List<int> sınıfı yapısında int türünden değişkenleri saklayabilmekteyiz. Tanımlayacağımız bu koleksiyon üzerinden
arama yapabilmek için List<T> sınıfı içerisinde FindAll() isimli bir metot yer almaktadır. FinAll fonksiyonunun prototipi
aşağıdaki gibidir.

using System.Collections.Generic;

public class List<T>


{
public List<T> FindAll(Predicate<T> match)
{... }
}

public delegate bool Predicate(T val);

Yukarıdaki kod blokları C# 2.0 ile birlikte gelen List sınıfı ve Predicate isimli temsilcinin bildirimlerini içermektedir.
FindAll metodunun amacı varolan bir koleksiyondan istediğimiz koşulları sağlayan alt bir kümeyi bulmak ve geriye
döndürmektir. Buradaki soru işareti kriterlerin nasıl verileceğidir? C# 1.1 de olsaydık yapabileceğimiz şey Predicate
temsilcisine uygun bir metot ile koşulları test edip geri döndürmektir. FindAll metodu kendi içinde her bir eleman için
Predicate ile temsil eden metodu (bizim yazdığımız metot) çağırarak kritere uyup uymadığını kontrol eder. Metodun
geri dönüş değer bool olduğundan true dönen değerleri kritere uygun kabul eder ve alt koleksiyona ekler. Boylece
istediğimiz kriterlere gore alt bir List<int> kümesi elde etmiş oluruz. Eğer C# 2.0 da isimsiz metotlar olmasaydı bu
işlemi C# 1.1 mantığıyla aşağıdaki gibi oluşturmamız gerekirdi.

- C# 1.1 Mantığı
static void Main()
{
List<int> sayilar = new List<int>();
sayilar.Add(1);
sayilar.Add(2);
sayilar.Add(3);
sayilar.Add(4);
sayilar.Add(5);
sayilar.Add(6);

Predicate<int> f = new Predicate<int>(KararVer);


List<int> ciftSayilar = sayilar.FindAll(f);
foreach (int i in ciftSayilar)
{
Console.WriteLine(i);
}
}

static bool KararVer(int deger)


{
return deger % 2 == 0;
}

Örneği çalıştırdığınızda ekrana 2,4,6 yazdığı görülecektir.

C# 2.0 da yukarıdaki örneği isimsiz metotları(anonymous methods) kullanarak daha sade bir şekilde çözebiliyoruz.
İsimsiz metotlar parametre olarak bir temsilcisi nesnesi bekleyen durumlarda da kullanılabildiği için yukarıdaki örneği
C# 2.0 da KararVer gibi bir metot tanımlamadan aşağıdaki gibi şekillendirebiliyoruz.

- C# 2.0 Mantığı
static void Main()
{
List<int> sayilar = new List<int>();
sayilar.Add(1);
sayilar.Add(2);
sayilar.Add(3);
sayilar.Add(4);
sayilar.Add(5);
sayilar.Add(6);

List<int> ciftSayilar = sayilar.FindAll( delegate(int val) {return val%2==0;} );

foreach (int i in ciftSayilar)


{
Console.WriteLine(i);
}
}

Yukarıdaki orneği çalıştırdığımızda yine aynı sonuc aldığımızı görürüz. İsimsiz metotlar sayesinde temsilci bekleyen
bir parametreyi metot tanımlamadan direkt metot gövdesi açıp tanımlayabiliyoruz.

C# 3.0 da ise bu örnek lambda ifadeleri, var deyimi ve kolkesiyon ilk atam değerleri kullanılarak aşağıdaki hale
geliyor.

- C# 3.0 Mantığı
static void Main()
{
var sayilar = new List<int>(){1,2,3,4,5,6}; //koleksiyon ilk atama , C# 3.0 a özgüdür.

var ciftSayilar = sayilar.FindAll( val => val % 2 ==0);

foreach (int i in ciftSayilar)


{
Console.WriteLine(i);
}
}

Yukarıdaki kod bloğunda bulunan FindAll metodunun parametresine Lambda İfadesi denilmektedir. Lambda ifadesi
aslında IL de bir fonksiyona denk düşmektedir.

=> imgesi artık bir operatör olarak ele alınmaktadır. val => val % 2 == 0 ifadesi ile geriye bool dönen ve int türünden
bir parametre alan bir fonksiyon tanımlamış oluyoruz. Üretilen değerin ve parametrenin tipi açıkca belirtilmemiş olsa
bile derleyici ifadeyi ayıklayarak buna karar vermektedir. İstersek ifadeyi şu şekilde de tanımlayabiliriz : (int val) =>
val % 2 == 0 yada (int val) => { return val % 2 == 0;} Birden fazla parametre alan lambda ifadeleri söz konusu ise
parametreler virgül ile aşağıdaki gibi tanımlanabilir.

(x, y) => x+y yada (int x,int y) => {return x+y;}

Lambda deyimleri genel olarak bu şekilde tanımlansa da lambda deyimleri ile ilgili bilinmesi gereken başka konularda
var. Özellikle metot aşırı yükleme ve otomatik tür dönüşümleri ile ilgili bazı kısıtlamalar mevcut. Butün bunları
inceleyebileceğini C# 3.0 Specification dökümanını aşağıdaki bağlantıya tıklayarak indirebilirsiniz.

C# 3.0 Specification dökümanını indirmek için tıklayınız.

C# 2.0 ve C# 3.0 Yeniliklerini Kullanan Faydalı Bir Örnek

Dilde yapılan diğer değişiklik olan sorgu ifadelerine(query expressions) geçmeden önce öğrendiğimiz yenilikleri
kullanarak faydalı bir örnek yapalım. Zaten bu örnek sorgu ifadelerini anlamımıza bir hayli yardımcı olacaktır.

Örnek uygulamada List<T> koleksiyonuna bir genişletme metodu ekledim ve boylece bu metot yardımıyla herhangi
bir koleksiyon üzerinden SQL deki where koşuluna benzer sorgulamalar yapma şansına sahip oldum. Biraz karışık ve
ilk bakışta gerçekten anlaşılması zor bir örnek oldu. İtiraf etmek gerekirse bende bunu yaparken epey zorlandım.
Ama yapıya alışınca ne kadar güçlü bir yapı olduğunu sizde farkedeceksiniz. Size tavsiyem yukarıdaki ilk 3 örneği
iyice hazmettikten sonra bu örneği incelemeniz. Örneğin çalışması için herhangi bir özel isim alanını eklemenize
gerek yok. C# 3.0 a eklenen dil özelliklerini kullanarak yaptım. Birazdan Query Expression yapısını gördüğümüzde
aslında bu ifadelerin arka planda neye dönüşmüş olduğunu daha net anlamış olacaksınız.

using System;
using System.Collections.Generic;
using System.Text;

namespace MyQueryExpression
{
class Program
{
static void Main(string[] args)
{
List<Personel> personeller = new List<Personel>{new Personel{Ad = "Ali",No = 3 }};

personeller.Add(new Personel{Ad = "Ali",No = 27 });


personeller.Add(new Personel{Ad = "Sefer",No = 5 });
personeller.Add(new Personel{Ad = "Ali",No = 6 });
personeller.Add(new Personel{Ad = "Oguz",No = 8 });

//SelectWhere List<T> sınıfına bizim eklediğimiz genişletme metodudur.


var aliOlanlar = personeller.SelectWhere(p => p.Ad == "Ali");
var nosuBestenBuyukOlanlar = personeller.SelectWhere(p => p.No > 5 );

foreach (Personel ali in aliOlanlar)


{
Console.WriteLine( "Ad : " + ali.Ad + " No:" + ali.No.ToString());
}
}
}

public delegate bool ConditionTester<T>(T val);

public static class MyExtensions


{
public static IEnumerable<T> SelectWhere<T>(this List<T> liste, ConditionTester<T> secici)
{
foreach (T val in liste)
{
if (secici(val))
{
yield return val;
}
}
}
}

public class Personel


{
public string Ad;
public int No;
}
}

Gördüğünüz gibi sadece bir temsilci(delegate) ve genişletme metodu(extension metot) ekleyerek herhangi türden bir
koleksiyon üzerinden esnek bir sorgulama işlemi yapabiliyorum. Birazdan inceleyeceğimiz sorgu ifadelerinde bunu bir
adım daha öteye taşıyacağız. Ancak bilmeniz gerekirki sorgu ifadelerinin altında yatan mantık yukarıdaki örnekteki
gibidir.

Yukarıdaki örnekte kafanıza takılan ve anlamakta güçlük çektiğiniz bir nokta olursa bana e-mail aracılığıyla
ulaşırsanız elimden geldiğince yardımcı olmaya çalışırım.

6 - Sorgu İfadeleri (Query Expressions)

C# 3.0 diline eklenmiş en önemli özellik sorgu ifadeleridir. Yukarıdaki örnekte verdiğimiz SQL stili sorgulamayı direkt
olarak dile entegre edilmiş haline sorgu ifadeleri denilmektedir. Belirli kriterlere göre varolan bir koleksiyon
kaynağından alt bir küme seçmek için metotları kullanmak yerine dile eklenen bu yapılar sayesinde herhangi bir SQL
dilinde yaptığımız sorgulara benzer sorgular hazırlayabilmekteyiz. Örneğin bir Personel koleksiyonunda numarası 5
den büyük olanları isim sırasına göre sıralayıp isimleri büyük harflerle gösterilmiş şekilde bir alt küme elde etmek için
aşağıdaki gibi bir deyim yazılabilmektedir.

using System;
using System.Collections.Generic;
using System.Text;

namespace LINQTest
{
class Program
{
static void Main(string[] args)
{
List<Personel> personeller = new List<Personel>();
personeller.Add(new Personel{Ad="Sefer",No=3});
personeller.Add(new Personel{Ad="Ali",No=6});
personeller.Add(new Personel{Ad="Mehmet",No=2});
personeller.Add(new Personel{Ad="Burak",No=16});
personeller.Add(new Personel{Ad="Oguz",No=10});

//var sonuclar = .. şeklinde de diyebilirdik.


IEnumerable<string> sonuclar = from val in personeller
where val.No > 5
orderby val.Ad
select val.Ad.ToUpper();

foreach (string ad in sonuclar)


{
Console.WriteLine( ad );
}
}
}
public class Personel
{
public string Ad;
public int No;
}
}

Örneği derleyip çalıştırdığınızda ekrana,

ALI
BURAK
OGUZ

yazdığını göreceksiniz. Gördüğünüz üzere herhangi bir tipten bir koleksiyon üzerinde esnek ve hızlı sorgulamalar
yapabiliyoruz. Yukarıdaki kodlarda kalın olarak işaretlenmiş where,orderby,from ve select gibi deyimlerin aslında arka
planda birer genişletme metoduna (extension method) denk geldiğini bilmemiz gerekir. Yani yukarıdaki kod derleyici
içindeki parser tarafından aslında önce aşağıdaki gibi çevrilmekte ve ardından derleme işlemi gerçekleşmekte.

Not 1: Dikkat ettiyseniz select, from deyimleri SQL diline göre ters çevrilmiş durumda.
Not 2: Yukarıdaki deyimler en temel LINQ yapısıdır. Daha karmaşık yapıları bir sonraki makalemde ele alacağım.

IEnumerable<string> sonuclar = from val in personeller


where val.No > 5
orderby val.Ad
select val.Ad.ToUpper();

IEnumerable<string> sonuclar = personeller.Where( val => val.No > 5).OrderBy(val => val.Ad).Select(val =>
val.Ad.ToUpper());

Gördüğünüz gibi herbir yapı aslında parametre olarak bir lambda ifadesi alan metottan başka birşey değil. Bu yapı
dikkat ettiyseniz bizim yaptığımız örnekteki SelectWhere genişletme metoduna çok benzemektedir. Bunun gibi C#
3.0 a eklenmiş SelectMany, Groupby gibi bir çok genişletme metodu daha bulunmaktadır. LINQ genel mimari
olarak lambda ifadeleri ve genişletme metotlarının üzerine kurulduğu için bunun gibi bir çok eklenti çok rahatlıkla
geliştirilebilmektedir. C# 3.0 geliştiren ekip ise bu elentileri dile entegre ederek bizlere kullanım kolalığı sağlamaktadır.

Bu makalede C# 3.0 ın yeniliklerinden ve LINQ mimarisi hakkında bilgiler vermeye çalıştım. Dile eklenen özellikler
genel olarak bu kadar olmasına rağmen henüz burada değinmeğim bir çok LINQ özelliği bulunmaktadır. Bir sonraki
makalemde LINQ elemanları hakkında daha geniş bilgi verip LINQ altyapısının veritabanlarına uyarlanmış hali olan
DLINQ ve XML verilere uyarlanmış hali olan XLINQ ten bahsedeceğim.

LINQ, DLINQ ve XLINQ elemanlarını daha detayaylı ele alacağım ikinci makalemde görüşene dek esen kalın...

C# 3.0 ve genel olarak LINQ hakkında detaylı bilgilere aşağıdaki adresten erişebilirsiniz.

http://msdn.microsoft.com/vcsharp/future/default.aspx