<?xml version="1.0" encoding="UTF-8"?> <rss
version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
><channel><title>Diyezon &#187; .net 2.0</title> <atom:link href="http://www.diyezon.com/tag/net-20/feed/" rel="self" type="application/rss+xml" /><link>http://www.diyezon.com</link> <description>programlama sanatı...</description> <lastBuildDate>Tue, 24 Jan 2012 00:13:26 +0000</lastBuildDate> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.3.1</generator> <item><title>Enine Boyuna Generics &#8211; Bölüm 2</title><link>http://www.diyezon.com/enine-boyuna-generics-bolum-2/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=enine-boyuna-generics-bolum-2</link> <comments>http://www.diyezon.com/enine-boyuna-generics-bolum-2/#comments</comments> <pubDate>Sun, 23 Sep 2007 20:24:43 +0000</pubDate> <dc:creator>Fatih Tolga Ata</dc:creator> <category><![CDATA[Delphi]]></category> <category><![CDATA[.net]]></category> <category><![CDATA[.net 2.0]]></category> <category><![CDATA[delphi.net]]></category> <category><![CDATA[generics]]></category> <category><![CDATA[sınıf]]></category><guid
isPermaLink="false">http://www.diyezon.com/?p=55</guid> <description><![CDATA[Bir önceki bölümde Generics hakkında bazı terminolojiler üzerinde durduk. Ayrıca ilk başta verdiğimiz örnek ile, bir sınıfı veya bir metodu object yaklaşımı ile nasıl genlleştirilebileceğini gördük. Önceki makaleyi okuduktan sonra objcet yaklaşımı ile Generics arasındaki farkı idrak ettiğinize inanıyorum. Ve Generics&#8217;in avantajlarını ve kolaylığını anladığınızı düşünüyorum. Bu bölümde Sınırlandırıcıları(Constraints) göstermeye çalışacağız. Hazırsanız buyrun. Sınırlandırıcılar(Kısıtlamalar, Constraints) [...]]]></description> <content:encoded><![CDATA[<p
align="justify">Bir önceki bölümde Generics hakkında bazı terminolojiler üzerinde durduk. Ayrıca ilk başta verdiğimiz örnek ile, bir sınıfı veya bir metodu object yaklaşımı ile nasıl genlleştirilebileceğini gördük. Önceki makaleyi okuduktan sonra objcet yaklaşımı ile Generics arasındaki farkı idrak ettiğinize inanıyorum. Ve Generics&#8217;in avantajlarını ve kolaylığını anladığınızı düşünüyorum.</p><p
align="justify">Bu bölümde Sınırlandırıcıları(Constraints) göstermeye çalışacağız. Hazırsanız buyrun.</p><p><span
id="more-55"></span></p><h1>Sınırlandırıcılar(Kısıtlamalar, Constraints)</h1><p
align="justify">Öyle olurki bazen, tip argümanlarınızın belli metodları ve özellikleri içermesini isteyebilrsiniz. Mesela çizim yapma özelliği olan sınıfların kolleksiyonunu tutan bir generic sınıf düşünün. İsmi de TCizebilenKolleksiyon gibi bir şey olsun. Bu generic kolleksiyona atayacağınız her elemanın bir çizim gerçekleştiren &#8220;Ciz&#8221; gibi bir metodunun olmasını isteyebilirsiniz. Bu durumda, tip parametresini belli arayüzler ile sınırlandırmanız gerekmektedir. Bu örneğimizi koda dökecek olursak, arayüzümüz şöyle bir şey olacak:</p><pre>
<pre class="brush: delphi">ICizebilen = interface
public
  procedure Ciz;
end;</pre></pre><p
align="justify">Bu arayüz ile sınırlandırılmış olan kolleksiyon sınıfımız da şöyle bir şey olabilir:</p><pre>
<pre class="brush: delphi">TCizebilenKolleksiyon&lt;T: ICizebilen&gt; = class
...
end;</pre></pre><p
align="justify">Bu durumda T parametresine atayacağımız her argümanın ICizebilen arayüzünün sahip olduğu özellik ve metodlara sahip olacağını garantilemiş oluyoruz.</p><p
align="justify">.Net ortamında kullanabilceğiniz bir çok arayüz bulunmaktadır. Bu arayüzler genelde &#8220;able&#8221; son eki ile biterler. &#8220;able&#8221; ekinin Türkçe karşılığı &#8220;-ebilen&#8221;, &#8220;-abilen&#8221; olarak düşünebilirsiniz.. ISerializable, IComparable, ICloneable, vs&#8230;</p><p
align="justify">Tip parametreleri birden fazla arayüz sınırlandırıcısı alabilir. Bu durumda tip parametreleri virgül yerine aynen prosedür ve fonksiyonların parametrelerinde olduğu gibi &#8220;;&#8221; noktalı virgül ile ayrılırlar. Mesela:</p><pre>
<pre class="brush: delphi">TSinif&lt;T: ISerializable; U: IColoneable&gt; = class</pre></pre><p
align="justify">gibi&#8230; Bu örneğe göre T parametresi ISerializable arayüzünü, U parametresi de IColoneable arayüzünü desteklemesi şarttır.</p><p
align="justify">Ayrıca, birden fazla sınırlandırıcı, tek bir tip parametresine atanabilir. Bu durumda bunlar, &#8220;AND&#8221; lojik mantığına göre tip parametresini sınırlandırırlar.</p><pre>
<pre class="brush: delphi">TSinif&lt;T: ISerializable, IColoneable&gt; = class</pre></pre><p
align="justify">gibi&#8230; Bu örnekte T parametresi hem ISerializable, hem de IColoneable arayüzlerini desteklemek zorundadır. Aynı şekilde prosedür ve fonksiyon parametrelerinde olduğu gibi aynı sınırlandırmaya sahip iki tip parametresini virgül ile ayrırak beraber yazabilirsiniz:</p><pre>
<pre class="brush: delphi">TSinif&lt;T, U: ISerializable&gt; = class</pre></pre><p
align="justify">gibi&#8230; Bu örneğe sınırlandırıcıya sahip olmayan bir parametre daha ekleseydik noktalı virgül ile ayırmamız gerekecekti:</p><pre>
<pre class="brush: delphi">TSinif&lt;T, U: ISerializable; Z&gt; = class</pre></pre><p
align="justify">gibi&#8230;</p><p
align="justify">Bunlar grammer ile ilgili kısımlardı. Peki derleyicinin davranışı nasıl olacak? Aşağıdaki örneğe bakalım:</p><pre>
<pre class="brush: delphi">TPrintableCollect&lt;T: IPrintable&gt; = class ...
...
TDeneme = class(IPrintable)
  procedure Print;
end;

THata = class
end;
...
var
  Calisan: TPrintableCollect&lt;TDeneme&gt;;
  Hatali: TPrintableCollect&lt;THata&gt;; //Syntax hatası: THata sınıfı IPrintable arayüzünü desteklemiyor.</pre></pre><p
align="justify">Gördüğünüzü gibi THata sınıfı IPrintable arayüzüne yabancı olduğu için tip argümanı olarak atadığımızda syntax hatası alıyoruz.</p><p
align="justify">Bununla beraber aynı mantık ile arayüz yerine bir sınıfı sınırlandırıcı olarak kullanabilirsiniz. Bu durumda generic sınıfımız ancak ve ancak sınırlayıcı olarak verdiğimiz sınıf ve alt sınıflarından tipleri alabilir. Mesela:</p><pre>
<pre class="brush: delphi">TBirSinif = class...
TBirAltSinif = class(TBirSinif)...
TBirKolleksiyon&lt;T: TBirSinif&gt; = class...</pre></pre><p
align="justify">Bu örneğimizde T tip parametresine ancak ve ancak TBirSinif ve ondan türeyen sınıflar argüman olarak atanabilir.</p><h2>Sınırlandırıcılarda Belirsizlik</h2><p
align="justify">İki adet sınırlandırıcı, bir tip parametresine atandığını düşünelim. Mesela:</p><pre>
<pre class="brush: delphi">TTest&lt;T: ISerializable, ICloneable&gt; = class
  BirNesne: T;
  procedure Klonla;
end;

procedure TTest&lt;T&gt;.Klonla;
begin
  BirNesne.Clone;
end;</pre></pre><p
align="justify">Derleyici &#8220;BirNesne&#8221; değişkeninin ISerializable ve ICloneable arayüzlerini desteklediğini biliyor. Ayrıca IClonable arayüzünde de Clone isminde bir metod olduğunu da biliyor. Bu yüzden Klonla metodunda Clone metodunu çağırırken herhangi bir çevirim işlemi yapmadık. Çünkü derleyici, Clone metodunun hangi arayüze ait olduğunu biliyor.</p><p
align="justify">Farz edelim ki Clone metodu, hem ISerializable hem de ICloneable arayüzlerinde bulunuyor olsun. Bu durumda Clone metodunu yukarıdaki gibi çağırdığımızda ne olacak? Derleyici bu durumda belirsizilik olduğuna dair bir hata mesajı gösterecektir. Bu belirsizliği ortadan kaldırmak için harici çevirim(explicit casting) yapmalıyız. Yani:</p><pre>
<pre class="brush: delphi">procedure TTest&lt;T&gt;.Klonla;
begin
  ISerializable(BirNesne).Clone;
  ICloneable(BirNesne).Clone;
end;</pre></pre><p
align="justify">Bu durumda, ilk Clone çağırımı ISerializable arayüzü üzerinden, ikincisi ise ICloneable arayüzü üzerinden gerçekleşecektir.</p><h2>Sınırlandırıcı Olarak constructor, class ve record Kullanmak</h2><p
align="justify">Eğer sınırlandırıcı olarak record gibi referansız tipler kullanacaksak bu durumda &#8220;record&#8221; ayrılmış kelimesini kullanıyoruz. Ama dikkat etmemiz gereken konu kullanacağımız tip argümanı nullable yani null değer alabilen bir tipten olmamalı. Mesela string nullable&#8217;dır ama Integer değildir.</p><p
align="justify">Aynı şekilde eğer sınırlandırıcımız sadece referanslı tipler olacaksa bu sefer de &#8220;class&#8221; ayrılmış kelimesini kullanmaktayız. Ayrıca kullanacağımız tip nullable olabilmeli. Yani tip argümanı olarak sınıfların yaninda string gibi nullable tipleri de kullanabiliriz. Bunları şu şekilde örneklendirelim:</p><pre>
<pre class="brush: delphi">TReferansiz&lt;T: record&gt; = class...
TReferansli&lt;T: class&gt; = class...
TBirRecord = record
end;

var
  Hatali1: TReferansiz&lt;string&gt;; //Hatalı, çünkü string nullable,
  Hatali2: TReferansli&lt;Integer&gt;; //Hatalı, Integer referanslı bir tip değil
  Uygun1: TReferansiz&lt;TBirRecord&gt;;
  Uygun2: TReferansiz&lt;Integer&gt;;
  Uygun3: TReferansli&lt;string&gt;; //string nullable bu yüzden uygun.
</pre></pre><p
align="justify">gibi&#8230;</p><p
align="justify">Constructor kelimse ise, sınırlandırıcıda kullanılan sınıfın mutlaka parametresiz bir constructor&#8217;a sahip olmasını şart koşmaktadır. Mesela:</p><pre>
<pre class="brush: delphi">TBirSinif = class
  constructor Create;
end;

TBirBaskaSinif = class

end;

TBirKolleksiyon&lt;T: constructor&gt; = class...
...

var
  Uygun: TBirKolleksiyon&lt;TBirSinif&gt;;
  Hatali: TBirKolleksiyon&lt;TBirBaskaSinif&gt;;</pre></pre><p
align="justify">Bu örnekte Uygun nesnesinde tip argümanı olarak TBirSinif tipini girdik. Ve derleyici bunu kabul etti. Çünkü TBirSinif parametresiz bir constructor&#8217;a sahip ve sınırlandırıcımız için uygun. Fakat Hatali nesnesinde tip argümanımıza girilen TBirBaskaSinif tipi parametresiz bir constructor&#8217;a sahip değil. Bu yüzden derleyici burada hata gösterecektir.</p><h1>Sonuç</h1><p
align="justify">Normalde Delphi.NET derleyicisi, generics ve .net 2.0&#8242;a tam destek vermekle beraber, bir çok bug da içeriyor. Gerçi bu cümleleri yazdığım sıralarda, RAD Studio 2007 daha 1 haftadır piyasada. Şu an bildiğim kadarı ile Rad Studio 2007&#8242;in çıkacak olan update&#8217;inde büyük çoğunlukla derleyici ve asp.net&#8217;deki düzeltmeler bulunacak. Derleyici düzeltmelerinde de pastanın büyük payını generics ile ilgili hatalar alacak. Bu yüzden generics ile uğraşırken &#8220;Internal Error XXXX&#8221; gibi hatalar ile karşılaşırsanız kafanızı duvarlara vurmayın. Çünkü internal error&#8217;lerin hepsi bug olarak kabul edilir. Böyle bir durumla karşılaştığınızda eğer yoksa QC&#8217;ye rapor edebilirsiniz.</p><p
align="justify">Fatih Tolga Ata © 2007</p><h2>Kaynaklar:</h2><ul><li>CodeGear&#8217;ın Delphi Parametrize Tipler ile İlgili Taslak Metinleri</li><li>.NET 2.0 SDK Yardım Dosyası</li><li>Microsoft Visual C# 2005 Step by Step, John SHARP, 2005 Edition</li></ul><p
align="justify"> ]]></content:encoded> <wfw:commentRss>http://www.diyezon.com/enine-boyuna-generics-bolum-2/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>Enine Boyuna Generics &#8211; Bölüm 1</title><link>http://www.diyezon.com/enine-boyuna-generics-bolum-1/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=enine-boyuna-generics-bolum-1</link> <comments>http://www.diyezon.com/enine-boyuna-generics-bolum-1/#comments</comments> <pubDate>Tue, 18 Sep 2007 03:58:02 +0000</pubDate> <dc:creator>Fatih Tolga Ata</dc:creator> <category><![CDATA[Delphi]]></category> <category><![CDATA[.net]]></category> <category><![CDATA[.net 2.0]]></category> <category><![CDATA[generics]]></category> <category><![CDATA[nesne]]></category> <category><![CDATA[sınıf]]></category><guid
isPermaLink="false">http://www.diyezon.com/?p=54</guid> <description><![CDATA[Bir iki önceki makalemizde, Delphi gramerine katılan generics ve parametrize tipleri yüzeysel olarak tanıtmıştık. Generics, RAD Studio 2007&#8242; nin çıkması ile artık sadece beta tester&#8217;larını değil, tüm Delphi programcılarını ilgilendiren bir konu olmuştur. Gerçi şu an için sadece .NET ortamında kullanabildiğimiz bu özellik bir sonraki sürümde Win32 için de kullanılabilir bir gramer olacaktır. Başlangıç için [...]]]></description> <content:encoded><![CDATA[<p
align="justify">Bir iki önceki <a
href="http://www.diyezon.com/?p=48">makalemizde</a>, Delphi gramerine katılan <em>generics</em> ve <em>parametrize tipleri</em> yüzeysel olarak tanıtmıştık. Generics, RAD Studio 2007&#8242; nin çıkması ile artık sadece beta tester&#8217;larını değil, tüm Delphi programcılarını ilgilendiren bir konu olmuştur. Gerçi şu an için sadece .NET ortamında kullanabildiğimiz bu özellik bir sonraki sürümde Win32 için de kullanılabilir bir gramer olacaktır. Başlangıç için <a
href="http://www.diyezon.com/?p=48">önceki makalemizi</a> okuyabilir ya da direk buradan başlayabilirsiniz. Zira bu bölümde Generics ile ilgili temel bilgiler vereceğiz.</p><p><span
id="more-54"></span></p><h1>Giriş</h1><p
align="justify">Generics&#8217;i doğru bir şekilde anlayabilmek için, hangi problemleri çözmek için dizayn edildiğini anlamakta yarar var. Bunun için ilk başta temel bir konudan ve bununla ilgili bir problemden bahsedelim.</p><p
align="justify">.Net ortamı için <em>object</em> tipini herhangi bir değer ya da değişken için referans olarak kullanabilirsiniz. Çünkü her bir referans tipi otomatik olarak <em>System.Object</em> sınıfından türetiilir. Delphi&#8217;nin özel tipleri bile .net ortamına geçtiğinde artık birer <em>object </em>olacaktır. Fakat bazı durumlarda <em>explicit casting</em> yapmadan <em>object </em>sınıfına atama yapmak derleyicinin hata üretmesine neden olabilir (Explicit ve Implicit terimlerine yabancı iseniz <a
href="http://www.diyezon.com/?p=52">buradaki makalede</a> ilgili başlığı bulabilirsiniz.). Bunun için <span
style="font-family: Courier New;">AUTOBOX</span> direktifini kullanmamız gerekebilir. Yani aşağıdaki gibi, Delphi&#8217;ye ait özel bir tipi, .NET&#8217;in <em>object</em> tipine <em>implicit </em>olarak atama yaptığımızda derleyici hata üretecektir.</p><pre>
<pre class="brush: delphi">var
  i: Integer;
  o: &amp;amp;Object;
begin
  o := i;</pre></pre><p>Derleyicinin hata üretmemesi için ya <span
style="font-family: Courier New;">AUTOBOX </span>kullanacağız ya da <em>explicit casting</em> uygulayacağız:</p><pre>
<pre class="brush: delphi">var
  i: Integer;
  o: &amp;amp;Object;
begin
  o := &amp;amp;Object(i); //Explicit casting
  {$AUTOBOX ON}
  o := i;</pre></pre><p
align="justify">Buradan çıkardığımız sonuç, her halükarda eğer .Net ortamından söz ediyorsak, ister Delphi tipi olsun ister olmasın, herşey <span
style="font-family: Courier New;">&amp;Object</span> (<em>System.Object</em>) sınıfından türemiştir. Ve bir şekilde tüm tipler, <em>object </em>nesnesine atanabiliyor.</p><p
align="justify">Biz bu bilgiliyi kullanarak sınıflarımızı ve metodlarımızı bir çok noktada <strong>genelleştirebiliriz</strong>. Mesela VCL&#8217;den hatırlayacağınız <em>TList</em> sınıfına benzer bir liste sınıfı hazırlayabilir ve <em>object</em>&#8216;in yukarıdaki anlattığımız özelliği sayesinde içinde istediğimiz tipte nesneler barındırabiliriz. <em>System.Collections</em> alanında bulunan <em>Queue</em>(kuyruk) sınıfı da bu tarz bir yapıya sahiptir(Kuyruğa ilk giren ilk çıkar.). Mesela aşağıdaki örnekte iki farklı tipi <em>Queue </em>nesnesinin bir elemanı yapıyoruz.</p><pre>
<pre class="brush: delphi">uses
  System.Collections, System.Xml;
  ...

{$AUTOBOX ON}
var
  b: TButton;
  s: XmlDocument;
  q: Queue;
begin
  q := Queue.Create();
  b := TButton.Create(nil);
  x := XmlDocument;
  q.Enqueue(b);
  q.Enqueue(x);</pre></pre><p><em>Queue </em>sınıfının <em>Enqueue </em>metodu, kuyruğa yeni bir <em>object </em>eklemeye yarar. <em>Enqueue </em>metodu <em>object </em>tipinde parametre aldığından her çeşit nesne bu metod ile kuyruğumuza eklenebilir. Bu örneğimizde <em>TButton </em>ve <em>XmlDocument </em>tipinde iki farklı nesneyi kuyruğa ekledik. Kuyruktan bir eleman çıkarmak için ise <em>Dequeue </em>metodunu kullanmamız gerekecektir. <em>Dequeue </em>metodu da aynen <em>Enqueue </em>metodu gibi <em>object </em>nesneleri ile çalışır. Yani <em>Dequeue </em>metodunun çıktısı bir <em>object </em>olacaktır. İşte bu noktada, <em>object </em>sınıfının özelliğinden dolayı <em>Queue </em>sınıfı ve bu iki metodu <strong>genel çapta</strong> kullanılabilir bir yapıdadır.</p><p>Yukarıdaki kodlara şunları ekleyip derlemeye çalışalım:</p><pre>
<pre class="brush: delphi">var
  ...
  ...
  cikanB: TButton;
  cikanX: XmlDocument;
begin
  ....
  ....
  cikanB := q.Dequeue; //ilk button girmişti, ilk de o çıkacak.
  cikanX := q.Dequeue;</pre></pre><p
align="justify">Bu kodu derlemeye kalkdığınızda &#8220;Incompatible types&#8230;&#8221; hatasını alacaksınız. Halbuki yukarıda <span
style="font-family: Courier New;">AUTOBOX </span>ile <em>implicit </em>çevirimi aktifleştirmiştik. Peki bu hatayı neden aldık?</p><p
align="justify">Birincisi, <span
style="font-family: Courier New;">AUTOBOX </span>sadece <em>object </em>nesnelerine atama yapılacağında işe yarıyor, <em>object </em>nesneleri başka bir nesneye atama yapılacağında değil. <em>Object </em>sınıfndan türemiş olan bir sınıfın nesnesi <em>object</em>&#8216;e atama yapacağınızda, derleyici bunu otomatik çevirebilir. Ama aksi durumda, <em>object </em>nesnesinin hangi sınıftaki bir nesneye dönüşeceğini kestiremez. Bu durumda <em>explicit</em> çevirim yapmak zorundayız. Bunun için sondaki iki satırı şu şekilde değiştirmeliyiz:</p><pre>
<pre class="brush: delphi">  ...
  cikanB := TButton(q.Dequeue);
  cikanX := XmlDocument(q.Dequeue);
  ShowMessage(cikanX.Name); //&quot;#document&quot;</pre></pre><p
align="justify">Peki kuyruktan çıkış sırasını yanlışlıkla değiştirseydik ne olurdu? Biliyoruz ki, kuyruk&#8217;ta ilk giren ilk çıkar. Yani örneğimize göre ilk olarak button girmişti ve ilk olarak da o çıkacaktır. Bu durumda sıralarını değiştirelim deneyelim:</p><pre>
<pre class="brush: delphi">  ...
  cikanX := XmlDocument(q.Dequeue);
  cikanB := TButton(q.Dequeue);
  ShowMessage(cikanX.Name);</pre></pre><p
align="justify">Bu kod derlenir fakat çalışma anında yanlış yaptığımızı gösteren bir hata alırız. Bu durumda <em>object </em>sınıfının bu genelleştirme özelliğini, bunun gibi yerlerde kullanmak, bir çok yanlışı ve dikkatsizliği de beraberinde getiriyor.</p><p
align="justify"><strong>Genelleştirilmiş </strong>sınıf ve metodlar oluşturmak için kullanılan bu <em>object </em>yaklaşımının diğer bir dezavantajı ise, <em>object </em>sınıfının diğer bir nesneye çevirim yapılması(unbox işlemi ya da unboxing de denilir) yada başka bir sınıfın <em>object </em>sınıfına çevirim yapılması(box ya da boxing yapılması) esnasında gereken ek hafıza ve işlemci zamanıdır. Yani her defasında <em>Enqueue </em>yapıldığında bir nesne <em>object </em>tipine dönüştürülecek ve her <em>Dequeue </em>yapıldığında ise <em>object </em>nesnesinin tipi başka bir nesneye dönüştürülecektir. Bu da ek işlem gücü ve hafızayı gerektirir.</p><p
align="justify">Sınıfları ve metodları genelleştirmede <em>object </em>yaklaşımının belki başka dezavantajlarda sayılabilir ama, bizim işimiz burada generics ve parametrize tipler. <em>Object </em>yaklaşımı kafamızın bir köşesinde yer etmişken, dilerseniz generics yaklaşımına bir göz atalım.</p><h1>Generics ve Parametrize Tipler(Parameterized Types)</h1><p
align="justify">Aslında Delphi programcıları bunu çok uzun süreden beri bekliyorlardı. Belki de .NET 2.0&#8242;a böyle bir özellik gelmeseydi, uzun bir süre daha Delphi böyle bir özellikten yoksun kalacaktı. Borland ya da CodeGear&#8217;ın .NET ortamına yaptığı yatırımları eleştirenler olmuştur. Fakat bu yatırımlar sayesinde hem Win32 hem de .NET üzerinde Delphi bir çok yeniliğe gitmiştir. <a
href="http://www.diyezon.com/?p=53">Buradaki makaleden</a> bu yeni özellikleri kısaca tanıyabilirsiniz.</p><p
align="justify">Gramere ve kullanışına geçmeden önce bir kaç terim üzerinde duralım. Terimler ilk başta kafa karıştırıcı gibi gelse de bu terimleri kullandıkça alışacağınıza inanıyorum. Bu terimleri önce veriyorum çünkü makale içerisinde bu terimler kullanılacak.</p><h2>Terminoloji</h2><p
align="justify"><strong>Parametrize Tip (Parameterized Type:):</strong> <em>Tip Paremetresi</em>ne ihtiyaç duyan bir çeşit tiptir. <em>Generic tip</em>, parametrize tipin daha çok bilinen ismidir. Ama literatürde ikisi de kullanılmaktadır. Aşağıdaki kodda &#8220;<span
style="font-family: Courier New;">Liste&lt;eleman&gt;</span>&#8221; sınıfı, bir <em>parametrize tip</em>tir.</p><pre>
<pre class="brush: delphi">type
  Liste&lt;eleman&gt; = class
    ...
  end;</pre></pre><p
align="justify"><strong>Tip Parametresi (Type Parameter):</strong> Bir <em>parametrize tip</em> veya metod başlık tanımlamasında, <em>parametrize tip</em>in veya metodun <span
style="text-decoration: underline;">kodlarında kullanılacak</span> olan bir tipi ifade eden bir <em>parametre</em>dir. Daha sonra bu parametreye bir <em>tip argümanı</em> bağlanacaktır. Aşağıdaki kodda &#8220;<em>eleman</em>&#8221; bir <em>tip parametresi</em>dir ve sınıfın kodlarında <span
style="text-decoration: underline;">kullanılacak</span> olan bir tipi ifade eder.</p><pre>
<pre class="brush: delphi">type
  Liste&lt;eleman&gt; = class
    ...
  end;</pre></pre><p
align="justify"><strong>Oluşturulmuş Tip (Instantiated Type, Constructed type):</strong> Parametre kümesi tanımlanmış olan bir <em>parametrize tip</em>tir. <span
style="font-family: Courier New;">Liste&lt;Integer&gt;</span> gibi&#8230;</p><p
align="justify"><strong>Tip Argümanı (Type Argument):</strong> &#8220;<em>Oluşturulmuş</em>&#8221; bir tip yapmak için gereken bir çeşit tiptir. Mesela <span
style="font-family: Courier New;">Liste&lt;Integer&gt;</span> bir <em>oluşturulmuş parametrize tip</em> ise, <span
style="font-family: Courier New;">Integer</span> bunun <em>tip argümanı</em>dır.</p><p
align="justify"><strong>Kapalı Oluşturulmuş Tip (Closed Constructed Type):</strong> Bir <em>parametrize tip</em>in tüm parametreleri, <strong>gerçek tip</strong> olan <em>argüman</em>lar ile çözümlenmiş ise bu tipe, <em>Kapalı Oluşturulmuş Tip</em> denir. <span
style="font-family: Courier New;">Liste&lt;Integer&gt;</span> <span
style="text-decoration: underline;">kapalıdır</span>, çünkü <span
style="font-family: Courier New;">Integer</span> <em>tip argümanı</em> <span
style="text-decoration: underline;">gerçek</span> bir tiptir.</p><p
align="justify"><strong>Açık Oluşturulmuş Tip (Open Constructed Type):</strong> Eğer bir <em>parametrize tip</em>in en az bir parametresi bir <em>tip parametresi</em> ise, bu tip bir <em>açık oluşturulmuş parametrize tip</em>tir. Ayrıca eğer <span
style="font-family: Courier New;">Liste&lt;T&gt;</span> parametrize tipinde <em>T</em> parametresi <span
style="text-decoration: underline;">bir sınıfı</span> içeren parametre ise <span
style="font-family: Courier New;">Liste&lt;T&gt;</span> açık oluşturulmuş bir tiptir. İleride örnekler yaptığımızda bu daha da pekişecektir.</p><p
align="justify"><strong>Oluşturma İşlemi (Instantiation):</strong> Derleyici, parametrize tiplerde tanımlı metodlar için gerçek işlem kodunu oluşturur ve kapalı tipler için gerçek virtual metod tablosunu oluşturur. Bu işlem <span
style="text-decoration: underline;">ön derleme</span> esnasında gerçekleşir. Bu işlem Win32&#8242;de <span
style="font-family: Courier New;">*.dcu</span> ve <span
style="font-family: Courier New;">*.obj</span> dosyalarını çıkarırken gereklidir. Fakat .Net ortamında gerekli değildir. Çünkü .Net oluşturulmuş tipler için gerekli tanımlamalara sahiptir. Bu yüzdendir ki, C++&#8217;da template oluşturduğunuzda, derleyici ilk başta template&#8217;li tipleri ayrı ayrı oluşturmak için ön derleme işlemine girişir. Anlaşılan o ki, Delphi&#8217;nin bir sonraki versiyonunda da Win32&#8242;de generics desteği verebilmek için buna benzer bir yönteme gidilecek. Her neyse&#8230;</p><p
align="justify">Bunlar dışında bir kaç terim daha var. Fakat daha fazla kafa karıştırmamak için, o terimleri ayrı başlıklar halinde ileride görelim. Dilerseniz önceden object yaklaşımı ile yaptığımız işlemleri şimdi de generics ile yapmaya çalışalım.</p><h1>Kullanımı</h1><p
align="justify">Kuyruk örneğimizi hatırlayacak olursanız, ekstradan tip çevirim işlemleri yapmıştık. Ayrıca tip güvenliğinin gerekli olduğundan ve bir dikkatsizlikte belli sorunların oluşabileceğinden bahsettik. Ayrıca fazladan gerçekleştirilen object&#8217;den bir başka tipe ve daha sonra da o tipden tekrar object&#8217;e çevirim yapılmasından dolayı(<em>box / unbox</em>), ekstra hafıza ve işlem gücü gerektiğinden bahsetmiştik.</p><p
align="justify">Bütün bunlara gerek duymadan, genelleştirilmiş sınıflar oluşturabilmek için parametrize tipleri ve generic yapısını kullanabiliriz. Generic sınıflar, tip parametresine sahip olduğundan dolayı, sadece <em>object </em>gibi bir tipe bağlı <span
style="text-decoration: underline;">kalmaz</span>. Böylece yukarıda bahsettiğimiz sıkıntıları da bertaraf etmiş oluruz.</p><p
align="justify">.Net 2.0 ile birlikte <em>System.Collections.Generic</em> alan adının altında bir çok yararlı generic sınıf tanımlanmıştır. Aşağıdaki kod parçasında parametrize <em>Queue </em>sınıf ile oluşturulmuş bir <em>Integer </em>kuyruğu ve bir <em>string </em>kuyruğu görmekteyiz.</p><pre>
<pre class="brush: delphi">uses
  System.Collections.Generic;

  ...
  ...

var
  SayiKuyruk: Queue&lt;Integer&gt;;
  YaziKuyruk: Queue&lt;string&gt;;
  Sayi: Integer;
  Yazi: string;
begin
  SayiKuyruk := Queue&lt;Integer&gt;.Create;
  YaziKuyruk := Queue&lt;string&gt;.Create;
  Sayi := 123;
  Yazi := &#039;Deneme&#039;;
  SayiKuyruk.Enqueue(Sayi);
  YaziKuyruk.Enqueue(Yazi);
  ...</pre></pre><p
align="justify"><em> </em></p><p
align="justify"><em> </em></p><p
align="justify"><em> </em></p><p
align="justify"><em> </em></p><p
align="justify">Gördüğünüz gibi, ne bir çevirim işlemi var ne de tipler uyuşuyor mu diye bir endişe&#8230; &#8220;<em>SayiKuyruk</em>&#8221; ve &#8220;<em>YaziKuyruk</em>&#8221; nesnelerinin ikisi de <span
style="font-family: Courier New;">Queue&lt;T&gt;</span> gibi bir <span
style="text-decoration: underline;">parametrize tip&#8217;den oluşturulmuş</span> tipten oluşturulmuştur <img
src='http://www.diyezon.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> . Terimlerimizde hatırlarsanız &#8220;<em>Kapalı oluşturulmuş tip</em>&#8220;ten bahsetmiştik. Derleyici bu örneğimizde <span
style="font-family: Courier New;">Queue&lt;T&gt;</span> tipinden iki adet <span
style="text-decoration: underline;">yeni tip oluşturmuştur</span>. Bunlardan birisi <span
style="font-family: Courier New;">Queue&lt;Integer&gt;</span> ve diğeri ise <span
style="font-family: Courier New;">Queue&lt;string&gt;</span> tipidir. Ve ikisi de <em>kapalı oluşturulmuş</em> bir tiptir. Ayrıca iki tip tamamen bir birinden <strong>bağımsız</strong> iki farklı tiptir!</p><p
align="justify">Bu örnekten ne öğrendik? Özet olarak, bir generic sınıfa atadığımız <em>tip argümanları</em>na göre(<em>Integer, string, vs..</em>) yeni bağımsız bir tip oluşturuyoruz. Ve bu oluşturulan tip, parametre olarak verdiğimiz argümanlara göre işlem yapıyor.</p><p
align="justify">Önceki Queue sınıfı, sadece <em>object </em>tipinde nesneler ile çalşıyordu. Bu sınıftan sadece bir adet vardı ve oluşturduğumuz nesneler hep aynı sınıftan oluşturuluyordu. Ama <em>generic Queue </em>sınıfında ise iş biraz değişiyor. Artık tanımladığımız farklı tip için ayrı bir sınıf oluşturuluyor. Bu yüzden örneğimizdeki <em>SayiKuyruk </em>ve <em>YaziKuyruk </em>nesnelerinin sınıfları aynı değildir! Derleyici her iki <em>tip argümanı</em> için de ayrı ayrı sınıflar oluşturmuştur. Tip argümanları gerçek tipler olduğu için de oluşturulan bu iki sınıf da <em>kapalı oluşturulmuş</em> tip olmuştur.</p><h1>Tanımlanması</h1><p
align="justify">Generic tiplerin tanımlanması kullanımı kadar kolaydır. Delphi&#8217;de sınıflar, interface&#8217;ler ve record&#8217;lar tip parametreleri ile birlikte tanımlanabilirler. Ayrıca metodlar ve prosedürel tipler de parametrize yapılabilir. Aşağıdaki sınıf tanımlamasına göz önüne alalım:</p><pre>
<pre class="brush: delphi">type
  TBirSinif = class
  public
    procedure BirSeylerYap(Parametre: string); overload;
    procedure BirSeylerYap(Parametre: Integer); overload;
    procedure BirSeylerYap(Parametre: Boolean); overload;
  end;</pre></pre><p
align="justify">Sadece bu sınıf ve metodları düşündüğümüzde aynı iş için üç farklı metod tanımlaması yapıyoruz. Ne için? Sadece bir tipin değişmesi yüzünden. Bir de ikinci bir parametre aldığını düşünün. Veya üç, dört&#8230; Ne yapacağız? 4&#8242;ün 3&#8242;lü kombinasyonunu alıp o kadar farklı metod tanımlaması mı yapacağız?</p><p
align="justify">Bunun yerine bu işi derleyiciye bırakıp, biz sadece tipler ile uğraşıyoruz. Yukarıdaki sınıfımızı parametrize olarak yeniden tanımlayalım:</p><pre>
<pre class="brush: delphi">type
  TBirSinif&lt;T, K, L&gt; = class
  private
    FBirOzellik: K;
  protected
    procedure SetBirOzellik(const Value: K);
  public
    procedure BirSeylerYap(Parametre: T);
    property BirOzellik: K read FBirOzellik write SetBirOzellik;
  end;</pre></pre><p
align="justify">Gördüğünüz gibi, <em>Integer string</em> gibi değişkenler yerine sınıfa eklediğim <em>tip parametreleri</em>ni kullanıyorum. Bu parametrize tipimizde 3 adet <em>tip parametresi</em> mevuct. Gerçi bu örnekte sadece ilk ikisini kullanıyoruz.</p><p
align="justify"><em>Bir genel kültür bilgisi mahiyetinde, ek olarak, bu sınıf derlendikten sonra </em><span
style="font-family: Courier New;">TBirGenericSinif`3</span><em> gibi bir şekle girecektir. Eğer tip parametre sayısı 4 olsaydı, son kısım &#8220;</em><span
style="font-family: Courier New;">`4</span><em>&#8221; olacaktı. Bu yüzden derlenmiş assembly&#8217;nizi ya da programınızı reflect ettiğinizde bu tarz şeyler görürseniz şaşırmayın. Her neyse&#8230;</em></p><p
align="justify">Önceden de bahsettiğimiz gibi yukarıdaki <em>TBirSinif </em>sınıfı ile <em>TBirSinif&lt;T, K, L&gt;</em> generic sınıfı birbirinden çok farklı şeylerdir. İsimleri aynı olabilir ama kesinlikle aralarında bir bağlantı yoktur. Aynı şekilde <em>TBirSinif&lt;Integer, string, Boolean&gt;</em> gibi bir <em>kapalı</em> oluşturulmuş sınıf, <em>TBirSinif&lt;string, string, Integer&gt;</em> gibi başka bir <em>kapalı</em> sınıftan çok çok farklıdır ve bağlantıları yoktur. Çünkü derleyici, <em>tip argümanları</em>na göre tipleri tekrar tekrar tanımlamaktadır.</p><h2>Generic Metodlar</h2><p
align="justify">Sınıflar gibi metodlar ve prosedürel tipler de parametrize olarak tanımlanabilir. Mesela:</p><pre>
<pre class="brush: delphi">type
  TBirProsedur2&lt;T&gt; = procedure(Param1, Param2: T) of object;
  TNormalBirSinif = class
    procedure BirProsedur&lt;X&gt;(Param1, Param2: X);
  end;

procedure TNormalBirSinif.BirProsedur&lt;X&gt;(Param1, Param2: X);
begin

end;</pre></pre><p
align="justify">Görüldüğü gibi parametrize olmayan bir tip içinde(<em>TNormalSinif</em>) parametrize bir metod tanımladık. Bunu yaparken aynen sınıflarda olduğu gibi metod isminden sonra tip parametrelerini giriyoruz. Aynı şeyi parametrize olan bir tip içinde de yapabilirdik. Ama burada karar size ait. Eğer generic bir sınıf içinde farklı parametrelerle tanımlamamız gereken metodlar olursa, bu şekilde parametrize edebiliriz. Yani:</p><pre>
<pre class="brush: delphi">type
  TBirSinif&lt;T&gt; = class
    ...
    procedure BirProc&lt;X&gt;(Param1: X; Param2: T);
  end;</pre></pre><p
align="justify">Görüldüğü gibi sınıf tanımlamasında <em>X</em> parametresi tanımlı olmadığı halde, metod tanımlamamızda kullanabiliyoruz. Peki bu gibi bir şeyi nasıl kullanacağız?</p><p
align="justify">Farkında iseniz bir kaç paragraf yukarıda verdiğimiz bir örneğin tam bir çözümlemesini yapmadık. Yani:</p><pre>
<pre class="brush: delphi">type
  TBirSinif = class
  public
    procedure BirSeylerYap(Parametre: string); overload;
    procedure BirSeylerYap(Parametre: Integer); overload;
    procedure BirSeylerYap(Parametre: Boolean); overload;
  end;</pre></pre><p
align="justify">Bu sınıfta &#8220;BirSeylerYap&#8221; metodu overload edilmiştir. Bu sınıfı generic yaparken şu şekilde bir tanımlama yapmıştık:</p><pre>
<pre class="brush: delphi">type
  TBirSinif&lt;T&gt; = class
  public
    procedure BirSeylerYap(Parametre: T);
  end;</pre></pre><p
align="justify">Burada her bir <em>kapalı tip</em> için sadece bir adet metodumuz olabiliyor. Yani mesela <em>TBirSinif&lt;Integer&gt;</em> gibi kapalı bir sınıf içinde sadece bir adet &#8220;<em>BirSeylerYap</em>&#8221; metodu vardır ve sadece <em>Integer </em>tipinde bir parametre almaktadır. Halbuki bizim esas yapmak istediğimiz her bir <em>kapalı sınıf</em> içinde overload yaptığımız tiplerin sınırlandırmasını <span
style="text-decoration: underline;">kaldırmak</span>. Sadece bir çeşit metod yerine birden fazla çeşitte parametre alan metodlarımız olması gerekiyor. Bu yüzden metodumuzu <strong>genelleştirmek </strong>için onu da parametrize ediyoruz:</p><pre>
<pre class="brush: delphi">type
  TBirSinif&lt;T&gt; = class
  public
    procedure BirSeylerYap&lt;X&gt;(Parametre: X);
  end;</pre></pre><p
align="justify">gibi&#8230; Bu şekilde bir metodun, istediğimiz kadar çeşidini overload yapmadan oluşturabiliriz. Mesela:</p><pre>
<pre class="brush: delphi">var
  BirNesne: TBirSinif&lt;Integer&gt;;
begin
  BirNesne := TBirSinif&lt;Integer&gt;.Create;
  BirNesne.BirSeylerYap&lt;string&gt;(&#039;Deneme bir string&#039;);
  BirNesne.BirSeylerYap&lt;Integer&gt;(123);
  BirNesne.BirSeylerYap&lt;Boolean&gt;(True);
  BirNesne.BirSeylerYap&lt;TForm&gt;(Form1);
  BirNesne.BirSeylerYap&lt;TButton&gt;(Button1);</pre></pre><p>gibi&#8230;</p><p
align="justify">Gördüğünüz gibi overload ile kısıtlı sayıda yaptığımız metod tanımlamalarını bu şekilde artırabiliriz. Bu da aynen sınıflarda olduğu gibi, metodlarımızı da genelleştirmemize imkan sağlıyor.</p><h1>Gelecek Bölümde</h1><p
align="justify">Gelecek bölümde Sınırlandırıcıları ya da başka yerlede göreceğiniz tabir ile Kısıtlamalar ya da Constraints tabirlerini göreceğiz. Diğer bölüme geçmek için <a
href="http://www.diyezon.com/?p=55">buraya</a> tıklayabilirsiniz.</p><p
align="justify">Her zamanki gibi yorum ve eleştirilerinizi bekliyorum.</p><p>Fatih Tolga Ata</p><h2>Kaynaklar:</h2><ul><li>CodeGear&#8217;ın Delphi Parametrize Tipler ile İlgili Taslak Metinleri</li><li>.NET 2.0 SDK Yardım Dosyası</li><li>Microsoft Visual C# 2005 Step by Step, John SHARP, 2005 Edition</li></ul> ]]></content:encoded> <wfw:commentRss>http://www.diyezon.com/enine-boyuna-generics-bolum-1/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>Delphi programcıları, Generics ile tanışıyor&#8230;</title><link>http://www.diyezon.com/delphi-programcilari-generics-ile-tanisiyor/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=delphi-programcilari-generics-ile-tanisiyor</link> <comments>http://www.diyezon.com/delphi-programcilari-generics-ile-tanisiyor/#comments</comments> <pubDate>Wed, 25 Jul 2007 08:55:16 +0000</pubDate> <dc:creator>Fatih Tolga Ata</dc:creator> <category><![CDATA[Delphi]]></category> <category><![CDATA[.net]]></category> <category><![CDATA[.net 2.0]]></category> <category><![CDATA[generics]]></category> <category><![CDATA[highlander]]></category> <category><![CDATA[list]]></category> <category><![CDATA[sınıf]]></category><guid
isPermaLink="false">http://www.diyezon.com/?p=48</guid> <description><![CDATA[Şu an betası test edilen Highlander sürümünde göreceğimiz generic tipler, aslında c++ programcılarına pek de yabancı olmayan bir terim. .Net 2.0 ile birlikte, managed kodlar generics ile tanıştı. Haliyle Delphi de, highlander sürümü ile birlikte .net 2.0&#8242;ı ve generics&#8217;i destekliyor. Ama IDE ve kod editörü tam manasıyla generics&#8217;e destek vermeyecek. Ama derleyici olarak generics&#8217;in tüm [...]]]></description> <content:encoded><![CDATA[<p
align="justify">Şu an betası test edilen Highlander sürümünde göreceğimiz generic tipler, aslında c++ programcılarına pek de yabancı olmayan bir terim. .Net 2.0 ile birlikte, managed kodlar generics ile tanıştı. Haliyle Delphi de, highlander sürümü ile birlikte .net 2.0&#8242;ı ve generics&#8217;i destekliyor. Ama IDE ve kod editörü tam manasıyla generics&#8217;e destek vermeyecek. Ama derleyici olarak generics&#8217;in tüm özelliklerinden faydalanabileceğiz. Özellikle generics için refactoring bulunmayacak. Ayrıca help insight &#8216;da da generic tipler &quot;&lt;&gt;&quot; şeklinde görünecek. Ayrıca editor, generic tipleri generic tip olarak nitelememekte. Generic tipi ayrı bir sınıf olarak almakta. Her neyse bu gibi sorunlar bir update ile ya da 2008&#8242;in ilk çeyreğinde çıkması beklenen Tiburon sürümünde halledilecektir. Önemli olan generic tipleri derleyici bazında tam olarak kullanabileceğimiz.</p><p>Bütün bunları geçelim ve generic tiplere yabancı olanlar için bir kaç küçük örnek verelim.</p><p><span
id="more-48"></span></p><pre>
<pre class="brush: delphi">TGenericClass&lt;T&gt; = class
private
  FProperty: T;
public
  property AProperty&lt;T&gt; read FProperty write FProperty;
end;</pre></pre><p>Basit bir generic sınıf tanımlaması bu şekilde. Bu sınıfı aşağıdaki gibi kullanabiliriz.</p><pre>
<pre class="brush: delphi">var
  AStringClass: TGenericClass&lt;string&gt;;
  AIntegerClass: TGenericClass&lt;Integer&gt;;
begin
  AStringClass := TGenericClass&lt;string&gt;.Create;
  AIntegerClass := TGenericClass&lt;Integer&gt;.Create;

  AStringClass.AProperty := &#039;Bu bir string&#039;;
  AIntegerClass.AProperty := 456;
end;</pre></pre><p>Burada T parametresi bir tipi ifade etmektedir. İçine koyacağımız tipe göre sınıfımız kendini şekillendirmektedir. İstersek sınıfmızı &lt;T, U&gt; gibi birden fazla tip ile tanımlayabiliriz. Önceden de dediğim gibi eğer fikirlerini değiştirmezlerse highlander sürümünde editör, generic tipleri normal bir tip gibi algılıyor. Yani siz &lt;T, U&gt; gibi tanımladığınız generic sınıfınızı kullanırken iki yerine bir parametre kullanırsanız delphi böyle bir tanımlamanın olmadığından felan bahsedecektir. Ama eksik parametre kullanıldığını söylemesi gerekmektedir. Bu da çok karmaşık uygulamalarda sizi şaşırtabiliyor.</p><p>Aslında generic tiplerin en çok kullanıldığı yerler belki de kolleksiyon tiplerindedir. Mesela:</p><pre>
<pre class="brush: delphi">var
  AStringList: List&lt;string&gt;;
  AStreamList: List&lt;TMemoryStream&gt;;
begin
  AStringList := List&lt;string&gt;;
  AStreamList := List&lt;TMemoryStream&gt;;

  AStringList.Add(&#039;Birinci sıradaki yazı&#039;);
  AStringList.Add(&#039;İkinci sıradaki yazı&#039;);
end;</pre></pre><p
align="justify">Bu List&lt;T&gt; sınıfını kullanabilmek için System.Collections.Generic&#8217;i uses kısmına eklemelisiniz. Yukarıda gördüğünüz işlem Delphi&#8217;de TList ve pointer&#8217;lar ile yaptığımız işlemleri daha basit bir şekilde yapmamıza yarıyor. List dışında, .net kütüphanesi bir çok generic tip barındırmaktadır. Ama şimdilik highlander&#8217;da generic&#8217;lerin nasıl olacağına dair bu kadar bilgi yeterli. Highlander çıktıktan sonra bununla ilgili bir makale buralarda olabilir.</p><p
align="justify">Yorumlarınızı bekliyorum.</p></p> ]]></content:encoded> <wfw:commentRss>http://www.diyezon.com/delphi-programcilari-generics-ile-tanisiyor/feed/</wfw:commentRss> <slash:comments>3</slash:comments> </item> </channel> </rss>
<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using memcached
Page Caching using memcached
Database Caching 1/15 queries in 0.027 seconds using memcached
Object Caching 425/445 objects using memcached

Served from: www.diyezon.com @ 2012-02-08 11:36:23 -->
