SİTE
İÇİ ARAMA |
|
Blogroll |
|
|
|
C# 3.0 : Dil Yenilikleri ve LINQ (Language Integrated Query) |
|
Gönderiliyor lütfen bekleyin... |
|
|
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.0a alışmadan ve C#
2.0ın getirdiği yenilikleri hazmetmeden C# 3.0 dan bahsediyor olmak aslında
Microsoftun 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 Amerikada C# dilinin mimarlarından olan
Anders Hejlsbergin 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.0a 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 Serverdaki 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.0a 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 PDCde 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 2007nin sonu yada
2008in 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 Hejlsbergin 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 Omeganı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 Omeganın Microsoftun 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.0daki 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?comda 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 javascriptte 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.0a 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 Şenyurtun 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.0daki 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.0a ö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.0a 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.0a 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 XLINQten 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
Kaynakça
- The LINQ Project, Anders Hejlsberg
- C# 3.0 Specification
Makale:
C# 3.0 : Dil Yenilikleri ve LINQ (Language Integrated Query) .NET 3.0 ve .NET 3.5 Özel Bölümü Sefer Algan
|
|
|
-
-
Eklenen Son 10
-
Bu Konuda Geçmiş 10
Bu Konuda Yazılmış Yazılmış 10 Makale Yükleniyor
Son Eklenen 10 Makale Yükleniyor
Bu Konuda Yazılmış Geçmiş Makaleler Yükleniyor
|
|
|