Delphi Win32 & Lambda Expressions
// 16 Mayıs 2009 // Delphi, Programlama
C# 3.0 ile birlikte gelen Lambda Expressionlar hakkında hemen hemen pek çok yerde makale yada yazıya rastlamak mümkün. Bu makalelerin bazılarında Lambda ifadelerin geleceğin programlama özelliği olduğu yönünde abartılı görüşler olsa da yine de faydalı ve olması gereken özellikler olduğu kanaatindeyim bende. Ancak bazı Lambdacıların da bilmesi gerekir ki bu programlama alemine kesinlikle yeni girmiş bir unsur değildir. Bazı programlama dillerinde bu yetenek çok uzun zamanlardan beri mevcut. Ancak maalesef Delphi’de henüz yok. En azından Win32 versiyonunda yok, Delphi Prism’de var.
O zaman bende kolları sıvadım ve tam anlamı ile Lambda Expressions gibi olmasa , onun gücüne yakınlaşamasa da, yine de benzer bir yapıyı kodlamak istedim. Lambda ifadelerinin genel kullanım amacı SQL sorgularında olduğu gibi bir veri kümesini filtrelemek olarak düşünülebilir. Bizde Delphi’de yazacağımız bir liste sınıfına bu özelliği kazandırmaya çalışacağız örneğimizde. Hatalarımız, eksiklerimiz olursa şimdiden affola diyerek başlayalım kodlamaya.
TOperator = (opEqual, opGreater, opSmaller, opDifferent, opLike); TMyList = class(TList) public function Where(const PropertyName, PropertyValue : Variant; Operator : TOperator = opEqual) : TMyList; function InheritsFrom(const aClass : TClass) : TMyList; end;
Yukarıdaki şablonumuzdaki fonksiyonların aynı sınıfı döndürmesi(TMyList) bizim ana noktamız olacak. Şimdi bu basit liste sınıfımızın içerisinde depolamak istediğimiz TPerson sınıfının şablonuna bir bakalım:
TPerson = class(TPersistent) private fName : String; fAge : Integer; public constructor Create(const AName : String; const AAge : Integer); published property Name : String read fName write fName; property Age : Integer read fAge write fAge; end; { TPerson } constructor TPerson.Create(const AName: String; const AAge: Integer); begin inherited Create; fName := AName; fAge := AAge; end;
Görüldüğü üzere bu da son derece basit bir sınıf. Şimdi liste sınıfımıza ait can alıcı metodları yazmaya başlayalım;
function TMyList.InheritsFrom(const aClass: TClass): TMyList; var iCounter : Integer; obj : TObject; begin Result := TMyList.Create; for iCounter := 0 to Count - 1 do begin obj := TObject(Items[iCounter]); if obj <> nil then if obj.InheritsFrom(aClass) then Result.Add(obj); end; end; function TMyList.Where(const PropertyName, PropertyValue: Variant; Operator : TOperator = opEqual): TMyList; var iCounter : Integer; obj : TObject; Info : PPropInfo; found : Variant; begin Result := TMyList.Create; for iCounter := 0 to Count - 1 do begin obj := TObject(Items[iCounter]); if obj <> nil then begin Info := GetPropInfo(obj, PropertyName); // obj nesnesinde PropertyName isimli bir property tanımlı mı ? if Info = nil then Continue; found := GetPropValue(obj, PropertyName); // tanımlı ise o property'nin variant türünden değerini al. case Operator of // karşılaştırmaları yap, uygun kayıtları dönüş listesine ekle. opEqual : if found = PropertyValue then Result.Add(obj); opGreater : if found >PropertyValue then Result.Add(obj); opSmaller : if found < PropertyValue then Result.Add(obj); opDifferent : if found <> PropertyValue then Result.Add(obj); opLike : if VarIsStr(found) and VarIsStr(PropertyValue) then if Pos( VarToStrDef(PropertyValue, '-'), VarToStrDef(found, '') ) > 0 then Result.Add(obj); end; // case end; // if obj <> nil then end; // for iCounter := 0 to Count - 1 do end;
Bu iki yöntem örneğimizin can damarları. Şimdi yöntemlerimizi de tanımladığımıza göre test edebiliriz.
procedure ShowResults(const List : TMyList); var iCounter : Integer; Person : TPerson; begin for iCounter := 0 to List.Count - 1 do if List.Items[iCounter] <> nil then if TObject(List.Items[iCounter]) is TPerson then begin Person := TPerson(List.Items[iCounter]); ShowMessage(TPerson(Person).Name + '/' + InttoStr(TPerson(Person).Age)); end else ShowMessage(TObject(List.Items[iCounter]).ClassName); end; procedure TForm1.Button1Click(Sender: TObject); var ret, mList : TMyList; begin mList := TMyList.Create; mList.Add(TPerson.Create('Tuğrul HELVACI' , 34)); mList.Add(TPerson.Create('Olcay DAĞLI' , 29)); mList.Add(TPerson.Create('Eşref BEKDEMİR' , 36)); mList.Add(TPerson.Create('Özkan DANACI' , 24)); mList.Add(TPerson.Create('Tuğrul TATLICI' , 18)); mList.Add(TPerson.Create('Tuncay BAKLAVACI' , 14)); mList.Add(TButton.Create(nil)); mList.Add(TEdit.Create(nil)); mList.Add(TListBox.Create(nil)); mList.Add(TList.Create); // Bir TComponent türevi değil mList.Add(TObject.Create); // Bir TComponent türevi değil ret := mList.Where('Name', 'Tu', opLike); if ret <> nil then begin ShowResults(ret); // Tuğrul HELVACI, Tuğrul TATLICI, Tuncay BAKLAVACI FreeAndNil(ret); end; ret := mList.Where('Name', 'Olcay DAĞLI'); if ret <> nil then begin ShowResults(ret); // Olcay DAĞLI FreeAndNil(ret); end; ret := mList.Where('Name', 'Tu', opLike). Where('Age', 14, opGreater). Where('Age', 30, opSmaller); if ret <> nil then begin ShowResults(ret); // Tuğrul TATLICI FreeAndNil(ret); end; ret := mList.InheritsFrom(TComponent); if ret <> nil then begin ShowResults(ret); // TButton, TEdit, TListBox FreeAndNil(ret); end; mList.Free; end; initialization RegisterClasses([TPerson]); end.
Not: uses kısmına RTTI’ya erişmek adına TypInfo’yu eklemeyi unutmayın ve RTTI’nın sadece TPersistent’ten türemiş nesnelerin published alanlarını bulabileceğini de hatırınızdan lütfen çıkartmayın.
Sevgiler, saygılar..
Evet güzel bir çalışma olmuş abi ellerine sağlık.
Dataset oluşturup 20.000 kaydın üzerinde kayıt denedim çat diye geldi kayıtlar. Performansda süper.
Büyük küçük harf duyarlı çalışıyor.
Vay be neler de yapıyormuş
Tuğrul hocam,
eline sağlık, Sadettin Bey’in web sitesindeki yorumun
üzerinden linki takip ettim,
fakat kuyu çok derinmiş
Eline sağlık…
Faydalı olabiliyor isem ne mutlu bize üstad. Çok ilginç bir kaç makale daha yazacağım sırada epey makale var kafamda, ama pek vakit bulamıyorum.
Tuğrul Hocam,
1- pdf olarak indirme olanağımız var mı makaleleri ?
2- Eline sağlık tekrar, böyle güzel bilgiler ancak böyle güzel beyinlerden çıkar
2- Estağfirullah.
1- Açıkçası PDF meselesi hiç aklıma gelmedi. Esasen makalelerin indirilmesinin istenmesi de aklıma gelmemişti Niyetim insanların indir-kullan yapmaları değil de birşeyleri öğrenmelerine yardımcı olmak olduğu için indirme hususu aklıma gelmemişti. Şimdi bir de PDF’e aktarmakla uğraşırsam makale yazma hevesim kaçabilir, arzu edersen ilerleyen zamanlarda yaparız birşeyler. Benim de elimde yok çünkü , aklıma geldikçe yazı editörünü açıp yazıyorum.
Merhaba,
yazının konusu olan linq ve lambda ile ilgili dokuman ararken burayı buldum.
bu konuyla ilgili bilgiler ve örnek kod için çok teşekkürler.
ufak bir düzeltme yapmak istedim, sanırım kodda bir leak var,
where komutu her çağrıldığında yeni bir liste oluşturuluyor fakat sadece en son oluşturulan liste hafızadan siliniyor.
Evet kodda leak olması gerçekten çok doğal. Çünkü ilgili sınıflar herhangi bir interface’i implemente etmiyorlar, olması gerekeken ise bir interface implementasyonu idi. Maksat sadece yeni ufuklar açmak ama yine de ilginize ve yorumunuza teşekkür ederim.