<?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; nesne</title> <atom:link href="http://www.diyezon.com/tag/nesne/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 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 7 ile Şimdiki Delphi Sürümleri Arasındaki Farklar</title><link>http://www.diyezon.com/delphi-7-ile-simdiki-delphi-surumleri-arasindaki-farklar/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=delphi-7-ile-simdiki-delphi-surumleri-arasindaki-farklar</link> <comments>http://www.diyezon.com/delphi-7-ile-simdiki-delphi-surumleri-arasindaki-farklar/#comments</comments> <pubDate>Mon, 13 Aug 2007 22:00:48 +0000</pubDate> <dc:creator>Fatih Tolga Ata</dc:creator> <category><![CDATA[Delphi]]></category> <category><![CDATA[abstract]]></category> <category><![CDATA[class helper]]></category> <category><![CDATA[class static]]></category> <category><![CDATA[delphi.net]]></category> <category><![CDATA[final metodlar]]></category> <category><![CDATA[fonksiyon]]></category> <category><![CDATA[for-in]]></category> <category><![CDATA[inline]]></category> <category><![CDATA[miras]]></category> <category><![CDATA[nesne]]></category> <category><![CDATA[nested classes]]></category> <category><![CDATA[operator overloading]]></category> <category><![CDATA[property]]></category> <category><![CDATA[record]]></category> <category><![CDATA[sealed]]></category> <category><![CDATA[sınıf]]></category> <category><![CDATA[strict private]]></category> <category><![CDATA[strict protected]]></category><guid
isPermaLink="false">http://www.diyezon.com/?p=53</guid> <description><![CDATA[Bildiğiniz gibi VCL, .NET ortamına taşınırken derleyici bazında bir çok değişikliğe ve geliştirmeye gidildi. Bu geliştirmeler, hem Delphi.NET derleyicisini hem bildiğimiz klasik Delphi for Win32 derleyicisini etkiledi. Tabi bu geliştirmeler, en çok biz programcıların işine yaradı. Bu makalemizde bu yeniliklere değinmeye çalışacağız. Bunlardan bir kısmını önceki makalelerimizde ayrıntılı olarak işlemiştik. Burada sadece bu sitede bahsetmediğimiz [...]]]></description> <content:encoded><![CDATA[<p
align="justify">Bildiğiniz gibi VCL, .NET ortamına taşınırken derleyici bazında bir çok değişikliğe ve geliştirmeye gidildi. Bu geliştirmeler, hem Delphi.NET derleyicisini hem bildiğimiz klasik Delphi for Win32 derleyicisini etkiledi. Tabi bu geliştirmeler, en çok biz programcıların işine yaradı.</p><p
align="justify">Bu makalemizde bu yeniliklere değinmeye çalışacağız. Bunlardan bir kısmını önceki makalelerimizde ayrıntılı olarak işlemiştik. Burada sadece bu sitede bahsetmediğimiz kısımlar bahsedilecek ve önceden bahsettiklerimize linkler içerecektir.</p><p><span
id="more-53"></span></p><h1>Operator Overloading:</h1><p
align="justify">Buradaki makalede ayrıntılı olarak işlenmiştir: <a
href="http://www.diyezon.com/?p=52">http://www.diyezon.com/?p=52</a></p><h1>Inline Belirleyicisi:</h1><p
align="justify">Derleyiciye tavsiye niteliğinde olan bu belirleyici (ya da direktif), fonksiyon ya da prosedürün kod çıktısında, çağrıldığı yere gömülmesini sağlar. Tavsiye niteliğinde diyorum çünkü, eğer prosedür ya da fonksiyon inline yapılmaya müsait değilse derleyici bu direktifi es geçecektir.</p><p
align="justify">Inline yapılmış prosedür ya da fonksiyon, &quot;call&quot;, &quot;ret&quot; gibi assembler komutlarına ihtiyacı olmadığı gibi, stack&#8217;ın push ve pop ile yedeğinin de alınmasına ihtiyaç yoktur. &Ccedil;ünkü inline yapılan fonksiyon, direk olarak çağrıldığı kısma yerleşecektir. Halbuki normal fonksiyonlarda call komutu ile hafızada başka bir kod kısmına dallanmaktadır. Ve burada stack&#8217;ın yedeği alınıp, fonksiyon sonunda yedek tekrar yüklenmektedir. Daha fazla bilgi için (<a
href="http://www.diyezon.com/?p=45">Delphi ve C++ Builder ile Assembler</a> ve <a
href="http://www.diyezon.com/?p=47">Fonksiyon &Ccedil;ağırım Mekanizmaları</a>).</p><p
align="justify">Inline prosedür ve fonksiyonda bu gibi işlemler yapılmadığından kod daha hızlı çalışacaktır. Ama her fonksiyon çağırımında fonksiyon kodları direk olarak çağrıldığı yere yerleşeceğinden, programınızın boyutu biraz büyüyecektir. Tanımlaması normal fonksiyon ve prosedür gibi olup sadece son tarafa inline belirleyicisi eklenir:</p><pre>
<pre class="brush: delphi">procedure MyProc(x:Integer); inline;
begin
    // ...
end;</pre></pre><h1>Strict Private</h1><p
align="justify">Sınıf kavramına katılan bu alan tipi, normal private alan gibidir. Tek fark bu alan daha da gizlidir <img
src='http://www.diyezon.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> Bu dediğimizin anlaşılabilmesi için private alanın ne olduğu bilinmesi gerek. Tabi ondan önce sınıfların ne olduğunu biliyorsunuzdur umarım(<a
href="http://www.diyezon.com/?p=40">Bileşen Yazım Klavuzu</a>nun ilk bölümleri sınıfları anlatmaktadır).</p><p
align="justify">Private sınıflar normalde, aynı unit içindeki başka sınıflar içinden erişilebilir. Strict Private ise gerçekten gizler. Yani aynı unit içinde bile olsa başka bir sınıf strict private alana erişemez.</p><h1>Strict Protected</h1><p
align="justify">Private için geçerli olan durumun aynısı protected için de geçerlidir. Strict Protected ise sadece aynı sınıf ve sınıfın çocukları tarafından görülebilirler. Aynı unit bile olsa başka bir sınıf bu alanı göremez.</p><h1>Metodlu Record&#8217;lar</h1><p
align="justify">Artık Recordlar için private, public gibi alanlar tanımlayıp procedure, function, constructor gibi metodlar tanımlayabiliyoruz. Ayrıca property&#8217;ler de tanımlanabiliyor. Yani aynı sınıflar gibi&#8230;</p><pre>
<pre class="brush: delphi">type
  TMyRecord = record
    type
      TBirTip = Integer; //tip tanımlaması
    var
      BirAlanDegiskeni: TColor;
    class var
      StatikDegisken: Integer;
    procedure BirProsedur();
    constructor Create;
    property Color: TColor read BirAlanDegiskeni write BirAlanDegiskeni;
    class property StatikOzellik: TBirTip read StatikDegisken write StatikDegisken;
  end;

constructor TMyRecord.Create;
begin

end;

procedure TMyRecord.BirProsedur;
begin
  ShowMessage(IntToStr(Color));
end;</pre></pre><h1>Abstract ve Sealed Sınıflar</h1><p
align="justify">Önceden abstract sınıf tanımlanamıyordu. Bunun yerine interface&#8217;ler kullanılıyordu. Ama bu her zaman işe yaramayabiliyor. Yabancı olanlar için kısaca abstract, kendisinde herhangi bir tanımlama ve kod bulunayan, <strong>kod kısmı</strong>, sınıflar için çocuk sınıflarda, metodlar için ise mirasçı metodlarda tanımlı olan bir yapıdır.</p><pre>
<pre class="brush: delphi">type
  TAbstractClass = class abstract
    procedure SomeProcedure;
end;</pre></pre><p
align="justify">Bu sınıfın kod tanımlaması TAbstractClass sınıfından türeyecek olan sınıflarda yapılacaktır.</p><p
align="justify">Sealed sınıflar ise, kısır sınıflardır. Yani artık sınıf hiyerarşisinde en sonda bulunan ve kendisinden herhangi bir türetme yapılamayacak olan sınıflardır.</p><pre>
<pre class="brush: delphi">type
  TSealedClass = class sealed
    procedure SomeProcedure;
end;</pre></pre><p
align="justify">Bu sınıftan başka bir sınıf türetilemez.</p><h1>Class Helper&#8217;lar</h1><p
align="justify">Buradaki makalede ayrıntılı olarak işlenmiştir: <a
href="http://www.diyezon.com/?p=50">http://www.diyezon.com/?p=50</a></p><h1>Class Statik Tipler, Değişkenler, Özellikler, Sabitler, Metodlar</h1><p
align="justify">Bazen olurki nesneyi tanımlamadan, sınıf içinde bulunan bazı değerlere erişilmesini istersiniz. Bu durumda erişilmesini istediğiniz şeyi, statik olarak tanımlamalısınız. Mesela aşağıdaki örneğe bakalım:</p><pre>
<pre class="brush: delphi">type
  TAClass = class
    strict private
      class var
        StatikDegisken: Integer;
    strict protected
      class function GetStatikOzellik: Integer; static;
      class procedure SetStatikOzellik(val: Integer); static;
    public
      class property StatikOzellik: Integer read GetStatikOzellik write SetStatikOzellik;
  end;

TAClass.StatikOzellik := 879;</pre></pre><p
align="justify">Burada gördüğünüz gibi TAClass sınıfından bir nesne oluşturmadan içindeki bir özelliğie eriştik. Class Static tekniğini kullanırken dikkat etmeniz gerken bir kaç önemli nokta şudur:</p><ul><li>Statik metod&#8217;lar içinde artık Self değişkenini kullanamazsınız. &Ccedil;ünkü sınıfa referans içeren bir nesne yoktur.</li><li>Statik metodlar ve özelliklerde ancak ve ancak statik olan değişken ve metodları kullanabilirsiniz.</li><li>Statik metodları virtual ya da dynamic olarak tanımlayamazsınız.</li></ul><p
align="justify">Bunun dışında bir sınıf içinde statik sabitler ve statik tipler de oluşturulabilir:</p><pre>
<pre class="brush: delphi">type
  TBirClass = class
  private
    type
      TBirStatikRecord = record
        BirAlan: string;
      end;
  public
    class var
      BirStatikRecord: TBirStatikRecord;
    const StatikSabit = &#039;Burada class kelimesini kullanmanıza gerek yok!!&#039;;
  end;

....
ShowMessage(TBirClass.StatikSabit);</pre></pre><p
align="justify">gibi&#8230;</p><h1>İç içe Geçmiş Sınıflar &#8211; Nested Classes</h1><p
align="justify">Artık bir sınıf tanımlamasının içinde başka bir sınıf tanımlanabiliyor:</p><pre>
<pre class="brush: delphi">type
  TDistakiSinif = class
  public
    type
      TIctekiSinif = class
      public
        procedure IctekiMetod;
      end;
      procedure DistakiMetod;
  end;

procedure TDistakiSinif.TIctekiSinif.IctekiMetod;
begin
  ...
end;</pre></pre><h1>Final Metodlar</h1><p
align="justify">Sealed sınıflar gibi final metodlar da bir sınıfın çocuk sınıflarında, final olarak tanımlanmış olan virtual metodun miras  alınamadığını ifade eder. Mesela:</p><pre>
<pre class="brush: delphi">TSonMetodluSinif = class(TBirAtaSinif)
public
  procedure SonMetod; override; final;
end;</pre></pre><p
align="justify">Bu tanımlamadan sonra artık SonMetod isimli metod, &quot;TSonMetodluSinif&quot; isimli sınıfın çocuk sınıfları tarafından override yapılamayacaktır. Final metodların sadece virtual metodlarda işe yaradığına dikkat edin.</p><h1>For-In Döngüsü</h1><p
align="justify">Artık bir dizi veya kolleksiyon içinde for-in döngüsü ile iterasyon yapılabilmekte:</p><pre>
<pre class="brush: delphi">
for DiziElemani in BirDizi do
begin
  ....
end;

for BirKarakter in BirString do
begin
  ...
end;

for BirKumeElemani in BirKume do
begin
  ...
end;

for BirKolleksiyonElemani in BirKolleksiyon do
begin
  ...
end;</pre></pre><h1>Sonuç</h1><p
align="justify">Yeni gelen özelliklerin unutmamış isem tamamına değinmeye çalıştım. Bunlara ek olarak Highlander çıktığında generic yani parametrize tiplere de ayrı olarak değineceğiz. Generics&#8217;in nasıl bir şey olduğunu merak edenler <a
href="http://www.diyezon.com/?p=48">buraya</a> tıklayarak meraklarını giderebilirler.</p><p
align="justify">Bunlarla ilgili uygulama yapıp geliştirmek sizlere kalmış. Buradaki bilgiler önfikir mahiyetindedir. Derleyici bazındaki yenilikler bunlar olmakla birlikte, VCL ve diğer alanlarda da bir çok yeniliğe gidilmiştir. Yeri geldikçe bunlardan da bahsedebiliriz.</p><p
align="justify">Yorumlarınız önemlidir, bekliyorum.</p></p> ]]></content:encoded> <wfw:commentRss>http://www.diyezon.com/delphi-7-ile-simdiki-delphi-surumleri-arasindaki-farklar/feed/</wfw:commentRss> <slash:comments>4</slash:comments> </item> <item><title>Delphi ve Operator Overloading</title><link>http://www.diyezon.com/delphi-ve-operator-overloading/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=delphi-ve-operator-overloading</link> <comments>http://www.diyezon.com/delphi-ve-operator-overloading/#comments</comments> <pubDate>Sun, 05 Aug 2007 22:00:40 +0000</pubDate> <dc:creator>Fatih Tolga Ata</dc:creator> <category><![CDATA[Delphi]]></category> <category><![CDATA[delphi.net]]></category> <category><![CDATA[nesne]]></category> <category><![CDATA[operator overloading]]></category> <category><![CDATA[sınıf]]></category><guid
isPermaLink="false">http://www.diyezon.com/?p=52</guid> <description><![CDATA[&#34;Operator Overloading&#34;(operator aşırı yükleme), Delphi&#8217;ye Delphi.NET ile birlikte gelen class helper&#8217;lar gibi yeni özelliklerden birisidir. Bu teknik, class helper&#8217;lar gibi hem Win32 hem de .NET için kullanabilirsiniz. Delphi&#8217;ye, belki de çok uzun zaman önce eklenmesi gereken bu özellik ile, herhangi bir sınıf veya record için toplama(+), çıkarma(-), çarpma(*) gibi operatörlere bazı özel anlamlar yükleyebiliyoruz. C++ [...]]]></description> <content:encoded><![CDATA[<p
align="justify">&quot;Operator Overloading&quot;(operator aşırı yükleme), Delphi&#8217;ye Delphi.NET ile birlikte gelen class helper&#8217;lar gibi yeni özelliklerden birisidir. Bu teknik, class helper&#8217;lar gibi hem Win32 hem de .NET için kullanabilirsiniz.</p><p
align="justify">Delphi&#8217;ye, belki de çok uzun zaman önce eklenmesi gereken bu özellik ile, herhangi bir sınıf veya record için toplama(+), çıkarma(-), çarpma(*) gibi operatörlere bazı özel anlamlar yükleyebiliyoruz. C++ programcılarının hiç de yabancı olmadıkları bu teknik ile kendimize özel veri tipleri tanımlayıp, bu tiplerin Integer, string gibi başka tipler ile etkileşimlerinin nasıl sonuç vereceğini belirleyebilirsiniz.</p><p><span
id="more-52"></span></p><h1>Giriş</h1><p
align="justify">Delphi programcılarının uzun zamandır en çok yakındıkları ve Delphi derleyicisi tasarımcılarının başını ağrıttıkları belli başlı konular vardır. Birisi şüphesiz parametrize tiplerdir(generics, c++ için STL). Highlander sürümü ile birlikte bu özellik de Delphi&#8217;ye kazandırılmış olacak. Diğerleri de nested tipler, class static tipler ve operator overloading olarak sıralanabilir. Parametrize tipler hariç diğerlerini hem Delphi, hem de Delphi.NET için şu anda kullanabiliyoruz.</p><p
align="justify">Bu makalemizde göreceğimiz operator aşırı yükleme veya operator overloading, sınıf ya da record&#8217;ların kullanımını büyük bir ölçüde genişletmektedir.  Delph.NET için hem record hem de class veri tipleri için operator overloading yapılabilirken, Delphi for Win32 için sadece record veri tiplerinde operator overloading yapılabilir. Ama bu kullanım bakımından o kadar da etki etmemektedir. Hatta çoğu durumda operator overloading için record kullanılmaktadır. Vereceğimiz örnekler sınıflar ile yapılmış olduğundan Delphi.NET ortamında denemelisiniz. Sınıflar ile örnek veriyorum, çünkü recordlar&#8217;dan farklı olarak yapılacak fazladan bir kaç işlem var. Mesela record&#8217;larda çoğu durumda Result çıkış değeri Record olduğundan, Create ile oluşturmanıza gerek yok.</p><h1>Ayran&#8217;nın Suyu Fazla mı Olmuş, Ne?</h1><p
align="justify">Operator overloading&#8217;i anlatabilmek için böylesine uçuk sayılabilecek bir örnek seçtim. Belki ayran içtikçe bu konuyu hatırlarsınız <img
src='http://www.diyezon.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /></p><p
align="justify">Şimdi 3 adet tipimiz olsun. TAyran, TYogurt ve TSu. TAyran sınıfı içinde hem TYogurt tipinde, hem de TSu tipinde iki adet özelliğimiz olsun. TTuz da olurdu ama şimdilik ayranımız tuzsuz olsun <img
src='http://www.diyezon.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /></p><pre>
<pre class="brush: delphi">TYogurt = class
  Miktar: Integer;
end;

TSu = class
  Miktar: Integer;
end;

TAyran = class
  Yogurt: TYogurt;
  Su: TSu;
public
  constructor Create;
end;

constructor TAyran.Create;
begin
  inherited;
  Yogurt := TYogurt.Create;
  Su := TSu.Create;
end;</pre></pre><p
align="justify">Şimdi diyelimki TAyran tipimize TYogurt ve TSu tiplerinde ekleme yapılabilsin. Ayrıca TYogurt ve TSu kendi aralarında toplanabilsin. Ayrıca bir de TAyran ile diğer tipler karşılaştırılmaya tabi tutulabilsin. Bu işlemleri siz, ayrı ayrı metodlar tanımlayarak ve bu metodları gerektiği yerde kullanarak gerçekleştirebilirisiniz. Ama operator overloading kullanarak aşağıdaki gibi işlemler yapabileceğiz:</p><pre>
<pre class="brush: delphi">var
  Yogurt: TYogurt;
  Su: TSu;
  Ayran: TAyran;
begin
  Yogurt := 15;
  Su := 5;
  Ayran := Yogurt + Su;
  Yogurt := Yogurt - 5;
  if Ayran &gt; Yogurt then
    ShowMessage(&#039;Ayrandaki yogurt miktarı daha fazla&#039;);
end;</pre></pre><p
align="justify">Nesne oluşturma kısımlarını konumuz dışında olduğu için atladım. Tabi ki bu işlemler, operator overloading olmadan hataya sebep olacaktır. &Ccedil;ünkü bir sınıf tipini kalkıp başka bir sınıf tipi ile topluyorsunuz, sonra bu sınıf tipine Integer ekliyorsunuz ve sonra da başka bir sınıf tipi ile karşılaştırmaya tabi tutuyorsunuz. Dediğim gibi bu işlemleri prosedür ve fonksiyonlarla da halledebilirsiniz. Ama bu işlemleri operator overloding üzerinden yaparsanız, kullanımda yukarıdaki gibi bir kolaylık sağlamış olacaksınız. Şimdi veri tiplerimiz ile yukarıdaki işlemleri gerçekleştirebilmek için gereken operator tanımlamalarını yapalım.</p><h1>Add ve Subtract</h1><p
align="justify">Şimdi TYogurt nesnesi için aşağıdaki tanımlamayı yapalım. Ama ondan önce TYogurt içinde TAyran ve TSu sınıflarına referanslarımız olduğundan ikisi için forward tanımlaması gerekmekte. &Ccedil;ünkü TAyran ve TSu, TYogurt&#8217;dan sonra tanımlanmıştır. Her neyse bu zaten nesne programlama konusu. Şu an bizim konumuzla alakası fazla yok.</p><pre>
<pre class="brush: delphi">
  TAyran = class; //forward tanımlama
  TSu = class; //forward tanımlama

  TYogurt = class
    Miktar: Integer;
    class operator Add(Yogurt: TYogurt; Su: TSu): TAyran; //Ayran := Yogurt + Su
    class operator Add(Yogurt1: TYogurt; Yogurt2: TYogurt): TYogurt; //Yogurt3 := Yogurt1 + Yogurt2
    class operator Subtract(Yogurt1: TYogurt; Yogurt2: TYogurt): TYogurt; //Yogurt3 := Yogurt1 - Yogurt2
  end;</pre></pre><p
align="justify">Gördüğünüz gibi üç adet satır ekledik. Bunlardan ilki &quot;+&quot; yani toplama operatorünün üzerine yazar. Bu class statik metod ile Add metodunun üzerine yazmak ile nesnemiz ile yapılacak olan her &quot;+&quot; toplama işleminde bu metod çağrılacaktır. Ama verdiğimiz kriterlere göre&#8230; Örneğimizde gördüğünüz gibi iki adet Add operatoru tanımlandı. Bunlardan ilki TYogurt ile TSu değerlerini topluyor ve sonucu TAyran olarak çıktı veriyor. İkincisi ise iki adet TYogurt nesnesin topluyor ve yine TYogurt cinsinden çıktı veriyor.</p><p
align="justify">Buradaki altın kural, eğer <strong>iki parametreli</strong> operator metodu var ise, tanımlayacağınız operator metodundaki parametrelerden <strong>en az birisi</strong> işleme girecek olan <strong>sınıftan</strong> olmalı. İki parametre alan çoğu operator metodları için bu mantık vardır. Bu yüzden bir operator&#8217;e overload yapacaksanız, kara kara hangi sınıfta tanımlıyacağınızı düşünmenize gerek yok. &Ccedil;ünkü işleme girecek olan herhangi bir sınıf bu metodun bir parametresi olacağından, işleme girecek olan herhangi bir sınıf içinde bu overload işlemini yapabilirsiniz. Mesela ilk Add tanımlamasını TSu sınıfında da yapabilirdik. &Ccedil;ünkü TSu da işleme girmektedir. Ama artık gerek kalmadı. &Ccedil;ünkü:</p><pre>
<pre class="brush: delphi">Ayran := Yogurt + Su;</pre></pre><p
align="justify">gibi bir ifade için bu Add metodu çağırılacaktır.</p><p
align="justify">Tek parametreli operator metodlarında ise aslında mantık ile parametresinin ne olacağını bilebiliyorsunuz. Zaten yanlış bir tanımlama yaptığınızda derleyici sizi uyaracaktır. Operator metodlarının parametreleri dahil tam listesi için yardım dosyasına müracaat etmelisiniz.</p><p
align="justify">En son satırdaki Subtract operator metodu ise &quot;-&quot; çıkarma işleminin görevini görmektedir. Burada gördüğünüz örnekte iki adet TYogurt nesnesi birbirinden çıkarılıp sonuç olarak TYogurt cinsinden çıktı veriliyor. Yani:</p><pre>
<pre class="brush: delphi">Yogurt3 := Yogurt1 - Yogurt2;</pre></pre><p>gibi.. Şimdi bu metodların kod kısımlarını da verelim.</p><pre>
<pre class="brush: delphi">class operator TYogurt.Add(Yogurt: TYogurt; Su: TSu): TAyran;
begin
  Result := TAyran.Create;
  Result.Yogurt.Miktar := Yogurt.Miktar;
  Result.Su.Miktar := Su.Miktar;
end;

class operator TYogurt.Add(Yogurt1, Yogurt2: TYogurt): TYogurt;
begin
  Result := TYogurt.Create;
  Result.Miktar := Yogurt1.Miktar + Yogurt2.Miktar;
end;

class operator TYogurt.Subtract(Yogurt1, Yogurt2: TYogurt): TYogurt;
begin
  Result := TYogurt.Create;
  Result.Miktar := Yogurt1.Miktar - Yogurt2.Miktar;
end;</pre></pre><p
align="justify">Gördüğünüz gibi Result değerlerini her defasında Create ile oluşturduk. &Ccedil;ünkü Result bir nesnedir. Ve Result ile atanacak olan nesne birbirinden farklıdır. İşte record kullanmanın bir yararı da burada. Create ile ikide bir oluşturmanıza gerek yok. Record kullanmanın tek dez avantajı, forward tanımlama yapamamanız. Ama bu sorun, her bir record&#8217;u ayrı dosyalara alınarak üstesinden gelinebilir. Ben bununla kafanızı karıştırmamak için sınıf&#8217;ları ve forward tanımlamaları kullandım. Ayrıa record&#8217;un bir avantajı da sınıf gibi private, public, protected alanlarda prosedür ve fonksiyon oluşturabilmenizdir. Gerçi bu özellik operator overloading ile aynı zamanda Delphi&#8217;ye kazandırılmıştır. Her neyse&#8230;</p><h1>Implicit ve Explicit</h1><p
align="justify">Şimdi diyelimki TYogurt tipindeki nesnemizi TAyran nesnesine dönüştüreceğiz. Yani TYogurt nesnesindeki miktarı, TAyran üzerine yazacaz. Bunun için TYogurt nesnesine şunu eklemeliyiz:</p><pre>
<pre class="brush: delphi">class operator Implicit(Yogurt: TYogurt): TAyran; //Ayran := Yogurt;</pre></pre><p
align="justify">Implicit operator metodu hangi sınıf veya record içinde tanımlanmış ise o sınıf veya record&#8217;u metodun Result kısmında bulunan sınıfa dönüştürür. Örneğimiz için bu Ayran değişkene Yogurt&#8217;u atamak ile olur. Bu metodun kodları ise örneğimize göre şöyle olabilir:</p><pre>
<pre class="brush: delphi">class operator TYogurt.Implicit(Yogurt: TYogurt): TAyran;
begin
  Result := TAyran.Create;
  Result.Yogurt.Miktar := Yogurt.Miktar;
end;</pre></pre><p
align="justify">Eğer sınıf için operator overloading kullanıyorsanız, burada ve diğer tanımlamalarda dikkat etmeniz gereken nokta parametre ile gelen nesneleri direk olarak Result içine atama yapmamanız. &Ccedil;ünkü bu taktirde sınıfın işaretçisini eşitlemiş olursunuz ve işler istemediğiniz noktalara gelebilir.</p><p
align="justify">Explicit operatorü ise <strong>mantık </strong>olarak aynıdır. Sadece kullanımda fark vardır. Yani yukarıdaki &quot;Ayran := Yogurt&quot; işleminde, kullanıcının böyle kolay bir şekilde eşitlemesini istemeyebiliriz. Yani direk böyle bir eşitleme yaptığında hata yapmış olabileceğini düşündürtmek için bu kullanıma izin vermeyebiliriz. Ve sadece type casting ile tip dönüşümüne izin verebiliriz. İşte bunu bize sağlayan operator Explicit&#8217;dir.</p><p
align="justify">&quot;Ayran := Yogurt&quot; eşitlemesini &quot;Ayran := TAyran(Yogurt)&quot; şeklinde yapabilmek için sadece yukarıda yazdığımız Implicit yazan yeri Explicit olarak değiştirin:</p><pre>
<pre class="brush: delphi">class operator TYogurt.Explicit(Yogurt: TYogurt): TAyran;
begin
  Result := TAyran.Create;
  Result.Yogurt.Miktar := Yogurt.Miktar;
end;</pre></pre><p
align="justify">Kod aynı kod, ama sadece Implicit yerine Explicit var. Bunu yapmakla artık &quot;Ayran := Yogurt&quot; çevirimi derleyici tarafından hatalı olarak görülecek ve &quot;Incompatible types&quot; yani uyumsuz tipler gibi bir hata verecektir. Böylece kullanıcıyı &quot;Ayran := TAyran(Yogurt)&quot; işlemini yapmaya zorlamış oluyoruz.</p><p
align="justify">Peki neden Implicit&#8217;i kaldırdık? Hem Implicit hem de Explicit operatorunu kullanamazmıydık. Kullanabiliridik. Ama Explicit çalışmazdı. &Ccedil;ünkü Implicit daima Explicit&#8217;den önceliklidir.</p><h1>Karşılaştırma</h1><p
align="justify"> Karşılaştırma işlemleri için bir çok operator vardır. Burada hepsine değinmemiz biraz zor. Sadece makalemizin başında verdiğimiz kodda kullandığımız &quot;&gt;&quot; büyüktür karşılaştırma operatoru için overload işlemini yapalım. Bu sefer dilerseniz TAyran sınıfımızda böyle bir tanımlama yapalım:</p><pre>
<pre class="brush: delphi">  TAyran = class
    Yogurt: TYogurt;
    Su: TSu;
  public
    constructor Create;
    class operator GreaterThan(Ayran: TAyran; Yogurt: TYogurt): Boolean;
  end;</pre></pre><p
align="justify">Karşılaştırma operatorlerini overload yaparken dönüş değerinin Boolean olmasına dikkat edin. Bu operator metodunu aşağıdaki gibi kodlayabiliriz:</p><pre>
<pre class="brush: delphi">class operator TAyran.GreaterThan(Ayran: TAyran; Yogurt: TYogurt): Boolean;
begin
  if Ayran.Yogurt.Miktar &gt; Yogurt.Miktar then
    Result := True
  else
    Result := False;
end;</pre></pre><p
align="justify">Yada daha kısa ve şık bir birçimde şöyle de olabilir:</p><pre>
<pre class="brush: delphi">class operator TAyran.GreaterThan(Ayran: TAyran; Yogurt: TYogurt): Boolean;
begin
  Result := Ayran.Yogurt.Miktar &gt; Yogurt.Miktar;
end;</pre></pre><p
align="justify">İçini nasıl doldurmanız gerektiği size kalmış. Ama burada Yogurt için de büyüktür operatorünü overload yapabilirdik. Bu durumda</p><pre>
<pre class="brush: delphi">Ayran.Yogurt.Miktar &gt; Yogurt.Miktar</pre></pre><p>yazmak yerine:</p><pre>
<pre class="brush: delphi">Ayran.Yogurt &gt; Yogurt</pre></pre><p
align="justify">yazabilirdik. Gerisi size kalmış.</p><h1>Sonuç</h1><p
align="justify">Burada değinmediğimiz bir çok operatöre aşırı yükleme yapabilirsiniz. Bunların tam listesi için yardım dosyasında &quot;Operator Overloading&quot; ile ilgili kısma bakmanız yeterli.</p><p
align="justify">Tabi burada verdiğimiz sınıflar için tek tek operator tanımlaması yaptığınızda ortalık biraz karışabiliyor. Bunların önüne geçmek için operator tanımlamalarını daha çok ata sınıflarda gerçekleştirmelisiniz. Böylece çocuk sınıflarda bu tanımlamaları bir daha yapmak zorunda kalmazsınız. Mesela örneğimizde TSu ve TYogurt sınıflarının her ikisinin de Miktar isminde bir özelliği mevcut. Bu iki sınıfı TSiviMadde gibi &quot;Miktar&quot; özelliği olan bir ata sınıftan türetebilirdiniz. Ve bu operator tanımlamalarını ata sınıf için yapıp, ayrı ayrı TSu ve TYogurt için yapmanıza gerek kalmazdı.</p><p
align="justify">Yorumlarınız önemlidir, bekliyorum.</p> ]]></content:encoded> <wfw:commentRss>http://www.diyezon.com/delphi-ve-operator-overloading/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Delphi.NET&#8217;in Yeni Oyuncağı &#8220;Class Helper&#8221;</title><link>http://www.diyezon.com/delphinetin-yeni-oyuncagi-class-helper/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=delphinetin-yeni-oyuncagi-class-helper</link> <comments>http://www.diyezon.com/delphinetin-yeni-oyuncagi-class-helper/#comments</comments> <pubDate>Wed, 01 Aug 2007 13:14:56 +0000</pubDate> <dc:creator>Fatih Tolga Ata</dc:creator> <category><![CDATA[Delphi]]></category> <category><![CDATA[.net]]></category> <category><![CDATA[class helper]]></category> <category><![CDATA[delphi.net]]></category> <category><![CDATA[nesne]]></category> <category><![CDATA[sınıf]]></category><guid
isPermaLink="false">http://www.diyezon.com/?p=50</guid> <description><![CDATA[.Net ortamı için sadece Delphi&#8217;de bulunan bir nesne özelliği ile tanışalım bugün, Class Helper(Sınıf Hizmetçisi, Yardımcısı, ya da ne isim verirseniz.). C# kullanıcıları, 2.0 sürümü ile benzer bir tip olan &#34;Partial Type&#34; ile tanıştılar. Ama partial tipler hali hazırda derlenmiş kodlar üzerinde işlem yapamazlar. Ama class helper&#8217;lar yapabilirler! Yani derlenmiş bir assembly&#8217; de bulunan bir [...]]]></description> <content:encoded><![CDATA[<p
align="justify">.Net ortamı için sadece Delphi&#8217;de bulunan bir nesne özelliği ile tanışalım bugün, Class Helper(Sınıf Hizmetçisi, Yardımcısı, ya da ne isim verirseniz.). C# kullanıcıları, 2.0 sürümü ile benzer bir tip olan &quot;Partial Type&quot; ile tanıştılar. Ama partial tipler hali hazırda derlenmiş kodlar üzerinde işlem yapamazlar. Ama class helper&#8217;lar yapabilirler! Yani derlenmiş bir assembly&#8217; de bulunan bir sınıf üzerine de class helper yazılabilir.</p><p
align="justify"> Nedir bu Class Helper? Yenilir mi, içilir mi, grameri nasıldır, ne işimize yarayacak? Bütün bu soruların cevaplarını bu kısa makalemizde vermeye çalışacağız.</p></p><p><span
id="more-50"></span></p><h1>Giriş</h1><p
align="justify">Hemen konuya girelim. Class Helper -yada sınıf hizmetçisi, ya da yardımcısı-, kendisinde bulunan bütün alanlarıyla, yardımcı olduğu sınıfı genişleten bir yapıdır, şeklinde tanımlanabilir. Class helper, mevcut bir sınıfı değiştirmeden veya bu sınıftan yeni bir sınıf türetmeden, bu sınıfa yeni özellikler, metodlar katmaya yarar. Böylece mevcut sınıfta hiç bir müdahaleye gerek kalmadan ve yeni bir sınıf türetmeden, mevcut sınıfımız istediğimiz şekilde şekillenecektir.</p><p
align="justify">Borland bu yapıyı, VCL kütüphanesini .NET ortamına geçirirken ihtiyaç duymuştur. &Ccedil;ünkü Win32&#8242;de tanımlanmış olan bir sınıf, hem .Net&#8217;i desteklemesi lazım hem de mevcut yapısını koruması lazım. İşte class helper, nesne programlamaya böyle bir esneklik getirmiştir.</p><h1>Grameri</h1><p
align="justify">Şimdi bu yapının grameri nasıldır ona bakalım:</p><pre>
<pre class="brush: delphi">TSinif = class
public
  procedure BirProsedur;
end;

TSinifYardimcisi = class helper for TSinif
public
  function BirFonksiyon: Boolean;
end;</pre></pre><p
align="justify">Ardından bu sınıfımızdan bir nesne oluşturalım:</p><pre>
<pre class="brush: delphi">var
  Nesne: TSinif;
begin
  Nesne := TSinif.Create;
  Nesne.BirFonksiyon;
end;</pre></pre><p
align="justify">Farkında iseniz TSinif adlı sınıfımızda &quot;BirFonksiyon&quot; isimli bir fonksiyon bulunmamakta. Ama bir class helper tanımlayarak, olmayan bu fonksiyonu sınıfımıza ekledik.</p><h1>Yanlış Kullanımlar ve Sınırlar</h1><p
align="justify">Nasıl ki programlamada her tekniğin bir yapabildiği olduğu gibi, tekniğe ters olan bazı şeyler de vardır. İlk önce yanlış kullanımlara bakalım:</p><ul><li>Mevcut .NET sınıflarını, kod tanımlamasını değiştirmeden genişletmeye çalışmak.</li><li>Mevcut .NET sınıflarını onlardan miras almadan genişletmeye çalışmak.</li><li>Sealed sınıfları genişletmeye çalışmak. (Sealed sınıflar, sınıf hiyerarşisinde kısır sınıflar olarak bilinirler. Yani sealed sınıflardan herhangi bir başka sınıf türetilemez.)</li><li>Büyük bir sınıf tanımlamasını birden fazla kaynak dosyaya rast gele bir şekilde bölmek.</li></ul><p
align="justify">Her ne kadar bunları yapabilseniz de, tavsiye edilmez ve yanlış kullanım kategorisindedir. Özellikle bir sınıf sealed olarak tanımlanmışsa, bunun elbette bir sebebi vardır. Bunu genişletmek, istenmeyen sonuçlara sebebiyet verebilir.</p><p
align="justify">Yapamayacağınız şeyler ise şunlardır:</p><ul><li>Bir class helper, genişlettiği sınıfın &quot;strict private&quot; olarak tanımlanmış alanına erişemez. Gerçi Delphi programcıları için bu, ne kadar doğru bir sınırlandırma olduğu tartışma konusu olmuştur ve olmaktadır.</li><li>Bir class helper, genişlettiği bir sınıf için interface tanımlayamaz.</li><li>Bir class helper için başka bir class helper tanımlanamaz.</li></ul><p
align="justify">Tabi yapılan en büyük yanlışlıklardan bir tanesi de, class helper&#8217;ları ayrı dosyada tanımladıktan sonra bunları ana sınıfın unitinde implementation alanında değil de interface alanında uses&#8217;a eklemek olacaktır. Bu da çapraz başvurudan dolayı hataya sebep olacaktır. &Ccedil;ünkü eklediğiniz helper unitinde interface alanında zaten uses kısmında ana sınıfın uniti eklenmiş durumdadır. Bu esasen class helper&#8217;larla alakalı bir hata olmadığından yukarıdaki maddelere eklemedim.</p><h1>Faydaları</h1><p
align="justify">Eğer birden fazla kişi aynı sınıf üzerinde çalışıyorsa, class helper&#8217;lar gerçekten çok işe yaramaktadır. Class helper kullanılmadığında, bir çok programcının yazdığı sınıfları bir sınıfta birleştirmek için bir kişinin uğraşması gerekmektedir. Bunu yapacak kişi de her yazılan sınıftaki özellik ve metodlara aşina olması şarttır. Class helper kullanıldığında, her programcı, sınıf içinde kendine ayrılmış kısım ile ilgili bir class helper yazar ve bir unit&#8217;e kaydeder. Geriye kalan sadece bunları uses&#8217;a eklemek ve derlemektir. Derleme işleminde, derleyici bu class helper&#8217;ları mevcut sınıfa ekleyerek birleştirip bir sınıf yapacaktır.</p><p
align="justify">Eğer sınıfınız bazı özel araçlar ile oluşturulmuş ise, class helper kullanarak bu oluşturulmuş olan kodda değişiklik yapmanıza gerek kalmayacaktır. &Ccedil;ünkü bu araç ile bir daha kodu üretmeniz gerektiğinde yazdığınız değişikliklerin kaybolmasına sebep olacaktır. Class helper kullanmadan bu tarz bir koda müdahale etmeniz zordur.</p><p
align="justify">Düşünün ki, ürettiğiniz yazılımın bir kaç versiyonu olacak. Mesela profesyonel, standart, temel(basic) gibi versiyonlarınız olacak. Profesyonel&#8217;de olan özellikler standart&#8217;a göre daha fazla olacak. Standartta olan özellikler de temel versiyona göre daha fazla olacak. Class helper kullanmadığınızda bu versiyonları oluşturmak için ayrı ayrı sınıflar oluşturmalısınız. Bu durumda temel sınıftaki bir özellik veya metodun değişmesi, bug&#8217;ların giderilmesi gibi işlemlerde aynı şeyleri hepsi için tek tek yapmalısınız. Birini birinden türetseniz dahi, mesela temel sınıfı ata sınıf kabul edip, diğerlerini ondan türetseniz dahi bu işinizi görmeyecek hatta daha da sıkıntılı bir duruma sokabilecektir. &Ccedil;ünkü nesnelerin kullanımı esnasında, ister istemez bir çok sorunla yüzleşeceksiniz. Bu sorunları çözmek için ek arayüzler ve sınıflar tanımlamak zorunda kalabileceksiniz. Halbuki class helper kullanıldığında sadece en temel olan sınıfı yazarsınız ve diğer sınıfları class helper olarak tanımlarsınız. Böylece mesela programın temel sürümünü derlemek için profesyonel ve standart class helper&#8217;larını projeden çıkarmanız yeterli olacaktır. Profesyonel sürümünü derleyeceğinizde ilgili class helper&#8217;ı projenize eklersiniz ve her şey bir çırpıda halledilmiş olur.</p><p
align="justify">Belki faydaları daha da artırılabilir. Ama kafanızda bir fikir oluşması için bunlar yeterli.</p><h1>(Güncelleme): Class Helper Önceliği</h1><p
align="justify">Anlatmayı unuttuğum bir kısım şimdi aklıma geldi <img
src='http://www.diyezon.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /></p><p
align="justify">Diyelim ki şöyle bir sınıf ve class helper olsun:</p><pre>
<pre class="brush: delphi">TSinif = class
private
  procedure MesajGoster;
public
  procedure BirSeylerYap;
end;

TSinifHelper = class helper for TSinif
public
  procedure MesajGoster;
end;</pre></pre><p
align="justify">Gördüğünüz gibi hem sınıfta hem de helper sınıfta da aynı isimde bir metod var. Ama sınıfta private olarak tanımlanmış bir metod, helper&#8217;da public olarak tanımlanmıştır. Peki burada hangisi geçerlidir? &quot;MesajGoster&quot; metodu tetiklendiğinde hangi metod çalıştırılacaktır? Aşağıdaki koda bakalım:</p><pre>
<pre class="brush: delphi">procedure TSinif.BirSeylerYap;
begin
  MesajGoster;
end;</pre></pre><p
align="justify">TSinif&#8217; ta bulunan &quot;BirSeylerYap&quot; metodumuzu bu şekilde yazdık. BirSeylerYap metodu çalıştığında, &quot;MesajGoster&quot; metodunu çağıracak. İşte burada çağrılacak olan daima önceliği fazla olan helper sınıftır. Yani burada TSinif.MesajGoster değil, TSinifHelper.MesajGoster metodu çağrılacaktır. Yani <strong>öncelik daima helper sınıfa aittir</strong>.</p><p
align="justify">Peki iki helper sınıf arasındaki öncelik neye göre belirlenir? Mesela yukarıdaki sınıfa ve helper&#8217;a ek olarak şunu da yazsa idik:</p><pre>
<pre class="brush: delphi">TSinifHelper2 = class helper for TSinif
public
  procedure MesajGoster;
end;</pre></pre><p
align="justify">TSinif isimli sınıfımızın MesajGoster metodu çağrıldığında hangi metod çağrılacaktır?</p><p
align="justify">Bundan önce class helper&#8217;ların daima sınıflardan öncelikli olduğunu gördük. Bu yüzden sınıfı eliyoruz. Diyelim ki TSinifHelper , TSinifHelper2&#8242;den daha önce yazılmış, yani daha yukarıda yazılmış. Bu durumda hangisi en sonra ya da en altta tanımlıysa onun sözü geçer. Yani <strong>en son tanımlanan helper daha önceliklidir</strong>.</p><p
align="justify">Bir öncelik daha kafamızı karıştırabilir. Diyelimki TSinifHelper, untHelper1 adlı dosyada ve TSinifHelper2 ise untHelper2 adlı dosyada. Bu durumda hangisi daha öncelikli olacak? Bu öncelik değeri, aslında bir önceki ile aynı mantıkta. <strong>Hangisi uses kısmında en sonda ise o önceliklidir</strong>.</p></p></p><h1>Sonuç</h1><p
align="justify">Bence, Delphi.NET ile birlikte gelen en iyi özelliklerden birisi class helper&#8217;lar. Özellikle takım çalışmasında büyük bir kolaylık sağlıyor. Sınıfın bir kısmını bir kişi, diğer tarafta sınıfın diğer kısmını yazan kişilerden habersiz görevini yerine getirebiliyor. Belki ilk başta klasik sınıf bilgimizden biraz garip gelebiliyor ama kullandıkça, ne kadar yararlı olduğunu görebiliyoruz.</p><p
align="justify">Sorularınız olduğunda buradaki yorum kısmına ya da delphiturkiye forumlarında Delphi.Net kısmına iletebilirsiniz.</p><p
align="justify">Kolay gelsin.</p></p> ]]></content:encoded> <wfw:commentRss>http://www.diyezon.com/delphinetin-yeni-oyuncagi-class-helper/feed/</wfw:commentRss> <slash:comments>6</slash:comments> </item> <item><title>Bileşen Yazım Klavuzu &#8211; 1</title><link>http://www.diyezon.com/bilesen-yazim-klavuzu-1/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=bilesen-yazim-klavuzu-1</link> <comments>http://www.diyezon.com/bilesen-yazim-klavuzu-1/#comments</comments> <pubDate>Sat, 28 Apr 2007 14:42:50 +0000</pubDate> <dc:creator>Fatih Tolga Ata</dc:creator> <category><![CDATA[Delphi]]></category> <category><![CDATA[bileşen]]></category> <category><![CDATA[bileşen kurulumu]]></category> <category><![CDATA[bileşen yazmak]]></category> <category><![CDATA[component]]></category> <category><![CDATA[event]]></category> <category><![CDATA[inherited]]></category> <category><![CDATA[kalıtım]]></category> <category><![CDATA[miras]]></category> <category><![CDATA[nesne]]></category> <category><![CDATA[nesne tabanlı programlama]]></category> <category><![CDATA[olay]]></category> <category><![CDATA[özellikler]]></category> <category><![CDATA[property]]></category> <category><![CDATA[sınıf]]></category> <category><![CDATA[TComponent]]></category> <category><![CDATA[TControl]]></category> <category><![CDATA[TGraphicControl]]></category> <category><![CDATA[türetim]]></category> <category><![CDATA[TWinControl]]></category><guid
isPermaLink="false">http://www.diyezon.com/?p=40</guid> <description><![CDATA[Delphi, gerçekten güçlü özelliklerle donatılmış bir geliştirme ortamıdır. Bir çok sınıflar ve yapılar ile IDE özelleştirilebilir. Kendi yazacağınız ya da dışarıdan kullanacağınız bileşenler ile programlama alanınızı özelleştirebilirsiniz. Hatta daha da ileri gidip Expert dediğimiz IDE eklentileri yazarak, IDE&#8217;ye olmayan yeni özellikler ekleyebilirsiniz. Bu makale serisinde VCL ve VCL.NET için bileşen yazımını göstereceğiz. Tabi ki, bileşen [...]]]></description> <content:encoded><![CDATA[<p
align="justify">Delphi, gerçekten güçlü özelliklerle donatılmış bir geliştirme ortamıdır. Bir çok sınıflar ve yapılar ile IDE özelleştirilebilir. Kendi yazacağınız ya da dışarıdan kullanacağınız bileşenler ile programlama alanınızı özelleştirebilirsiniz. Hatta daha da ileri gidip Expert dediğimiz IDE eklentileri yazarak, IDE&rsquo;ye olmayan yeni özellikler ekleyebilirsiniz. Bu makale serisinde VCL ve VCL.NET için bileşen yazımını göstereceğiz. Tabi ki, bileşen yazımına değinirken Delphi&rsquo;nin sahip olduğu belli başlı Nesne Programlama tekniklerine de değinmeden geçmeyeceğiz. Tercih ettiğimiz dil Object Pascal&rsquo;dır. Ama C++&rsquo;a da kodlar çevrilebilir.</p><p
align="justify">Ve tavsiyem başka bir bileşen kullanacağınıza kendi bileşeninizi kendiniz yazın! Nasıl mı? Cevabı işte bu makalede&#8230;</p><p><span
id="more-40"></span></p><div></div><div><p><a
href="http://www.diyezon.com/?p=40">Bölüm 1</a> &#8211; <a
href="http://www.diyezon.com/?p=41">Bölüm 2</a> &#8211; <a
href="http://www.diyezon.com/?p=42">Bölüm 3</a></p><h1>Giriş</h1></div><p
align="justify">Öyle bir yazılım geliştirme ortamı düşünün ki, kendi yazdığınız sınıfları tanıyıp kendi bünyesine alabiliyor. Öyle ki, kendi editörleri ile, bilinen bazı tiplerde sınıfınızı daha kolay kullanır hale getiriyor. Ve hatta kendi görsel dizayn aracı ile, sizin sınıfınızı bütünleşik olarak kullanabiliyor. İşte bu geliştirme ortamlarından bir tanesi ve belki de en güçlüsü Delphi&rsquo;dir.</p><p
align="justify">VCL&rsquo;de bileşen dediğimiz zaman akla gelen ilk şey, VCL&rsquo;in <strong>tanıyabildiği</strong> sınıflardır. VCL&rsquo;in bir bileşeni tanıyabilmesi için belli başlı kriterler mevcuttur. Bu kriterlerden en önemlisi şüphesiz, nesnenin <font
face="Courier New">TComponent</font> sınıfından ya da alt sınıflarından türemesidir.</p><p
align="justify">Öyle ise, VCL&rsquo;de bir bileşen, sınıf hiyerarşisi <font
face="Courier New">TComponent</font> ata sınıfına dayanan nesnelerdir, diyebiliriz. VCL.NET&rsquo;de de bu olay böyledir. Tek fark <font
face="Courier New">TComponent</font> sınıfının nereden türediğidir. Ama bileşen yazıyor isek bu bizi o kadar da çok ilgilendirmiyor. &Ccedil;ünkü <font
face="Courier New">TComponent</font> sınıfının ataları ile pek uğraşmayacağız.</p><div><h1>DesignTime ve RunTime</h1></div><p
align="justify">Bileşen yazımında bilmemiz gereken iki kavram. DesignTime yani tasarım zamanı, programı derleyip çalıştırmadan önceki tasarım aşamasıdır. Bileşenlerin, özelliklerini değiştirip düzenleyebildiğiniz bu aşamada, bileşenler IDE tarafından kısmen çalıştırılırlar. RunTime yani çalışma zamanı ise, programı derleyip çalıştırdıktan sonraki kısımdır. Bu aşamada IDE, devreden çıkmıştır ve bileşenleriniz çalışmaya başlamıştır. Bu aşamda IDE&rsquo;nin tek müdahale edebildiği kısım debug işlemleridir.</p><p
align="justify">İleride göreceğimiz belli özellikler ile, DesignTime ve RunTime üzerinde ayrı ayrı işlem yapabileceksiniz. Böylece tasarım zamanında bileşeniniz farklı davranacak, çalışma zamanında farklı davranacaktır.</p><div><h1>Bileşen Hiyerarşisi</h1></div><p
align="justify">VCL&rsquo;in bileşen olarak tanıdığı sınıfların <font
face="Courier New">TComponent</font> sınıfından türemesi gerektiğini gördük. Peki bundan sonra olaylar nasıl gelişiyor?</p><p
align="justify">Bildiğiniz gibi iki tip bileşen vardır. Görülebilen(<s>Görsel</s>) ve Görünmeyen(<s>Görsel olmayan</s>) bileşenler.<em>(Türkçeyi &ndash;sala bindirip &ndash;sele verdiler. Y. Bülent Bakiler)</em></p><p
align="justify">Görülebilen bileşenler, çalışma zamanında form üzerinde görülebilen bileşenlerdir. Bu bileşenler <strong><font
face="Courier New">TControl</font></strong> sınıfından türerler.</p><p
align="justify">Görünmeyen bileşenler ise <font
face="Courier New">TControl</font> sınıfından türemeyen herhangi bir <font
face="Courier New">TComponent</font> bileşenidir. Normalde sadece DesignTime&rsquo;da görünürler. Fakat bazı görünmeyen bileşenler, RunTime&rsquo;da etkileri bulunmaktadır. Ama bunlar çalışma zamanında görünseler bile görülebilen bileşen sınıfına girmezler. Mesela TPopupMenu ve TMainMenu, bu tarz bileşenlerdendir. Her ne kadar bazı makalelerde bu tarz bileşenler kısmi görünür olarak nitelendirilseler de biz bunları da görünmeyen olarak nitelendireceğiz.</p><p
align="justify">Kısacası bileşenleri Görülebilen(Visible) yani <font
face="Courier New">TControl</font> sınıfından türeyen bileşenler ve Görünmeyen(Non-Visible) bileşenler yani TControl&#8217;den türemeyen bileşenler olarak iki kısma ayırıyoruz.</p><p
align="justify">Tasarım zamanında görülebilen ve görünmeyen bileşenleri ayırmak kolaydır. Böylece hangisi <font
face="Courier New">TControl</font>&rsquo;den türemiş hangisi türememiş anlaşılabilir. Mesela <font
face="Courier New">TImage</font>, <font
face="Courier New">TButton</font> gibi görülebilen bileşenleri tasarım zamanında görünen şekli üzerinde oynama yapabiliyorsunuz. Ama <font
face="Courier New">TTimer</font> bileşeni form&rsquo;un üzerine eklendikten sonra, bileşeni temsil eden sadece bir kutucuk göreceksiniz.</p><div><p><strong><font
face="Courier New">TWinControl</font> ve <font
face="Courier New">TGraphicControl</font></strong></p></div><p
align="justify">Dedik ki, <font
face="Courier New">TComponent</font> sınıfından türeyen nesneleri, VCL bileşen olarak tanıyabilir. Ayrıca İşletim Sistemi&rsquo;nin tanıyabileceği sınıflar da mevcuttur. İşletim Sistemi tanıdığı sınıflara kolay ulaşmak için onlara birer numara atar. Bu namaraya <strong>Handle </strong>diyoruz. Eğer bir bileşenin Handle numarası var ise, bu bileşen İşletim Sistemi tarafından tanınabilmektedir. Herhangi bir programdan bu Handle numarası bilindiği takdirde, ilgili sınıfa ulaşilabilir.</p><p
align="justify"><font
face="Courier New">TControl</font> sınıfının iki önemli çocuk sınıfı vardır. Bunlar <font
face="Courier New">TWinControl</font> ve <font
face="Courier New">TGraphicControl</font>. <font
face="Courier New">TWinControl</font>,yukarıda bahsettiğimiz gibi, İşletim Sisteminin tanıyabildiği bileşen türlerindendir. Ve Handle numarasına sahiptir. Bu sınıftan türeyen bileşenler de Handle numarasına sahip olacaklardır. <font
face="Courier New">TForm</font>, <font
face="Courier New">TButton</font>, <font
face="Courier New">TPanel</font>, <font
face="Courier New">TCheckBox</font>, <font
face="Courier New">TComboBox</font>, <font
face="Courier New">TStaticText</font> bu tarz bileşenlerdendir.</p><p
align="justify">TGraphicControl sınıfları ise aksine Handle numarasına sahip değillerdir. Ve İşletim Sistemi, bunları sadece resim olarak görür. <font
face="Courier New">TImage</font>, <font
face="Courier New">TBevel</font>, <font
face="Courier New">TLabel</font> bu tarz bileşenlerdendir. <font
face="Courier New">TControl</font> sınıfının, <font
face="Courier New">TGraphicControl</font> sınıfından tek farkı, <font
face="Courier New">TGraphicControl</font>&rsquo;de çizim yapabilmeniz için bir Canvas nesnesi tanımlanmıştır.</p><p
align="justify">Öyle ise eğer Görülebilen bileşen yapmak istiyorsak önümüzde iki seçenek bulunmakta. Handle numarası alacak ya da almayacak. Handle numarası alması bileşene ek külfet getirecektir. Eğer Windows API&rsquo;leri ile bileşen üzerinde işlem yapmayacaksanız, ya da diğer bileşenler ile bu bileşeni etkileşimli bir şekilde kullanmayacaksanız her zaman için <font
face="Courier New">TGraphicControl</font> seçiminiz olsun. Ama az önce saydığımız işlemeleri yapacaksanız, bileşeninizin bir Handle numarasına ihtiyacı olacaktır.</p><p
align="justify">Mesela <font
face="Courier New">TPanel</font> gibi bir bileşen içine diğer bileşenleri gömecekseniz, bileşeniniz <font
face="Courier New">TWinControl</font>&#8216;dan türemelidir. Ya da bileşeninize SetWindowRgn gibi bir api ile değişik şekiller verecekseniz, yine <font
face="Courier New">TWinControl</font> sınıfını ebeveyn sınıf olarak kabul etmelisiniz.</p><p
align="justify">Bu örnekler artırılabilir. Bileşen yazımında mesafe katettikçe bu ayrımı yapmak sizin için zor olmayacaktır.</p><p
align="justify">Ayırca <font
face="Courier New">TGraphicControl</font> nesneleri, işletim sistemi tarafından tanınmadığı için, Handle numarası olan bir container yani bir taşıyıcı nesneye ihtiyaç duyarlar. Mesela form üzerine bir adet Image ve bir adet Panel ekleyin. Image nesnesi Handle numarasına sahip olmadığından hiç bir zaman panel&rsquo;in üzerine geçemiyecektir, daima altında kalacaktır. Ta ki, Handle numarası olan bir taşıyıcı nesne içine konulana kadar. &Ccedil;ünkü Handle numarası olmadan işletim sistemi bileşeni tanıyamaz ve hangisinin altta hangisinin üstte olacağını belirleyemez. Aynı şekilde bir Label da Panel, Button gibi bir bileşenin üstüne çıkamaz. Ama StaticText eklediğinizde button&rsquo;unun üzerine çıkabileceğini göreceksiniz. Eğer altında ise sağ tuşa tıklayıp &ldquo;Bring to Front&rdquo; yapabilirsiniz. <font
face="Courier New">TStaticText</font>, <font
face="Courier New">TWinControl</font>&rsquo;den türemiştir, <font
face="Courier New">TLabel</font> ise <font
face="Courier New">TGraphicControl</font>&rsquo;den türemiştir. Ek olarak, çok luzumu olmadıkça <font
face="Courier New">TStaticText</font> kullanılmamalıdır. &Ccedil;ünkü TWinControl sınıfları daha fazla hafıza ve daha fazla işlem gücü gerektirirler.</p><p
align="justify">Bu iki sınıf dışında, bu iki sınıftan türeyen başka sınıflardan da bileşen oluşturabilirsiniz. Mesela <font
face="Courier New">TMemo</font> sınıfından türeyen bir başka sınıf yazarak, <font
face="Courier New">TMemo</font>&rsquo;nun mevcut özelliklerinin üzerine yenilerini ekleyebilirsiniz. Ya da <font
face="Courier New">TLabel</font> gibi bir GraphicControl sınıfından türeyen bir bileşen yaparak <font
face="Courier New">TLabel</font>&rsquo;a mesela link özelliği ekleyebilirsiniz. Yoksa önceden tanımlanmış bir şeyi tekrar tanımlamanıza gerek yoktur.</p><div><h1>Nesne Tabanlı Programlama</h1></div><p
align="justify">Burada bahsedeceğimiz kısım, bileşen yazımında lüzumlu olan bazı nesne işlemleridir. Bu konu hakkında daha fazla bilgi alabilmek için başka makalelere göz atabilirsiniz.</p><div><p>Genel olarak bir sınıfın yapısı şu şekildedir.</p></div><div><pre>
<pre class="brush: delphi">TMyClass = class(TAnchestorClass)
private
protected
public
published
end;</pre></pre></div><div></div><div></div><div></div><div></div><div></div><div></div><p
align="justify">Bu tanımlama, <strong>type </strong>bloğunda bulunmalıdır. <strong>Implementation </strong>alanında ise bu sınıfın tanımlamaları bulunacaktır.</p><p
align="justify">Bu örnekte <font
face="Courier New">TAnchestorClass</font> sınıfından <strong>türeyen </strong>bir <font
face="Courier New">TMyClass </font>sınıfı tanımladık. Bunun dışında herhangibir method ya da özellik eklemedik.</p><div
align="justify">Gördüğünüz gibi sınıfımızda 4 adet alan bulunmaktadır.</div><p
align="justify"><font
face="Courier New"><strong>private</strong></font> alanında, sadece sınıfımızın için kullanılacak olan ve dışarı ile bağlantısı olmayacak olan değişkenler ve metodlar bulunacaktır. Gerek nesne tanımlandıktan sonra, gerekse <font
face="Courier New">TMyClass </font>sınıfından türeyen başka bir sınıf içinden, <font
face="Courier New"><strong>private</strong></font> alanı erişilebilir olmayacaktır.</p><p
align="justify"><font
face="Courier New"><strong>protected</strong></font> alanı ise yine <font
face="Courier New"><strong>private</strong></font> alana benzemektedir. Tek fark bu alana sadece çocuk sınıflar erişebilir. Yani <font
face="Courier New">TMyClass </font>sınıfından türeyen herhangi bir sınıf<font
face="Courier New"><strong> </strong><strong>protected</strong></font> alanında tanımlanmış olan özellik ve metodlara erişebilecektir.</p><p
align="justify"><font
face="Courier New"><strong>public</strong></font> alanı, gerek nesne tanımlandıktan sonra, gerekse çocuk sınıf tanımlamalarında görülebilen alandır. Yani <font
face="Courier New"><strong>private</strong></font> alanın tam ters özellikte bir alandır.</p><p
align="justify"><strong>published</strong> alanı ise Delphi için özel bir alandır. Bu alan IDE tarafından kullanılabilir olan özellikleri içerir. Bu alana eklediğiniz özellikler IDE&rsquo;de Object Inspector&rsquo;da görünecektir. Ayrıca eğer özelliğin kalıcılığı sağlanmış ise, IDE bu özelliğe ait değerleri ve verileri Dfm ya da Nfm dosyaları içine kaydedebilir. Özelliklerin kalıcılığını gelecek bölümlerde bahsedeceğiz.</p><div><p><strong>Constructor ve Destructor</strong></p></div><p
align="justify">Bir fonksiyon ya da prosedür tanımlamayı biliyoruz. Sınıf içinde bu tanımlamalar şu şekilde olacaktır.</p><div><pre>
<pre class="brush: delphi">interface

type
TMyClass = class(TAnchestorClass)
private
protected
public
  procedure MyProc(Param: string);
published
end;

implementation

procedure TMyClass.MyProc(Param: string);
begin
  ShowMessage(Param);
end;</pre></pre></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><p
align="justify">Sınıfımızın oluşturma zamanını ya da yok edilme zamanını kontrol edebilmemiz için iki ayrılmış kelime bulunmaktadır. <font
face="Courier New"><strong>Constructor</strong></font> ve <font
face="Courier New"><strong>Destructor</strong></font>. Bunlarda aynen <font
face="Courier New"><strong>procedure</strong></font> ve <font
face="Courier New"><strong>function</strong></font> gibi çalışırlar. Tek fark, <font
face="Courier New"><strong>constructor</strong></font>&rsquo;lar çağrıldığında sınıfımızından yeni bir nesne oluşturulacaktır. Aynı şekilde <strong><font
face="Courier New">destructor</font></strong> çağrıldığında ise nesne yok edilecektir. Object Pascal, istediğiniz kadar <font
face="Courier New"><strong>constructor</strong></font> ve <font
face="Courier New"><strong>destructor</strong></font> oluşturmanıza izin vermektedir. Örnek bir tanımlamayı şimdi görelim.</p><div><pre>
<pre class="brush: delphi">interface

type
TMyClass = class
private
protected
public
  constructor Olustur(Parametre: string);
  destructor YokEt;
published
end;

implementation

constructor TMyClass. Olustur (Parametre: string);
begin
  ShowMessage(&#039;Nesne Oluşturuldu. Oluşturma parametresi :&#039; + Parametre);
end;

destructor TMyClass.YokEt;
begin
  ShowMessage(&#039;Nesne yok edildi&#039;);
end;</pre></pre></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div
align="justify"><p>Daha sonra bu sınıfımızdan bir nesne oluşturmak için:</p></div><div><pre>
<pre class="brush: delphi">var
  MyObject: TMyClass;
begin
  MyObject := TMyClass.Olustur(&#039;Nesneden merhabalar&#039;);
  MyObject.YokEt;
  ShowMessage(&#039;Nesne yok edildi mi &#039; + BoolToStr(Assigned(MyObject), True));
end;</pre></pre></div><div></div><div></div><div></div><div></div><p
align="justify">Genel olarak mecbur olmasanız da standartlaşmış olan bazı isimlendirmeler mevcuttur. Nesneleri oluşturmak için kullanacağınız constructor için &ldquo;Create&rdquo; ve yok etmek için kullanacağınız destructor için &ldquo;Destroy&rdquo; tabirleri kullanılmaktadır. Bu isimlendirmeler VCL&rsquo;de önceden beri kullanıldığı için, oluşturulan diğer sınıflarda da bu isimlendirmeler kullanılmıştır. Hem ileride başka bileşenler ile sorun yaşamamak için hem de başka programcılar&rsquo;ın bileşeninizi rahat kullanabilmesi için standartları takip etmek faydalıdır. Bu yüzden biz de makalemizde constructor için Create ve destructor için Destroy isimlerini kullanacağız.</p><div><p><strong>Özellikler</strong></p></div><p
align="justify">Delphi&rsquo;de çok öncelerden beri var olan ve çoğu programlama dillerinin bile yeni yeni sahip oldukları &ldquo;özellikler&rdquo;, değişkenlerin farklı bir çeşitidir.</p><p
align="justify">Öyle bir değişken düşünün ki, değişkene veri atamaya kalktığınızda bir metod çalışsın ve değişkenden veri çekmeye çalıştığınızda ise başka bir metod çalışsın yada belirleyeceğiniz bir başka değişkenden veriyi okusun. İşte bu tarz işlemlere izin veren özel değişkenlere &ldquo;özellik&rdquo;(property) diyoruz.</p><div><p>Genel olarak bir özellik aşağıdaki gibi tanımlanır:</p></div><div><pre>
<pre class="brush: delphi">property MyProp: Integer read FMyProp write SetMyProp;</pre></pre></div><p
align="justify">Burada bilmemiz gereken 3 önemli alan vardır.</p><p
align="justify">Birincisi özelliğin tipini belirlediğimiz kısımdır. Özelliğe atayacağınız tip, diğer bölümlerde kullanılacak olan metod ve değişkenlerin tipleri ile aynı olmalıdır.</p><p
align="justify">İkinci alan olan <font
face="Courier New"><strong>read</strong></font> alanına, veri okunacağı zaman nereden okuyacağını bildiriyoruz. Bu örnekte özelliğimizden veri çekilmeye çalışıldığında, veri otomatik olarak <font
face="Courier New">FMyProp</font> değişkeninden çekilecektir.</p><p
align="justify">&Uuml;çüncü alanımız olan <font
face="Courier New"><strong>write</strong></font> alanında ise, özelliğimize veri yazılacağı vakit nereye yazılacağını belirliyoruz. Örneğimizde veri, <font
face="Courier New">SetMyProp</font> metoduna yollanacaktır.</p><p
align="justify">Önceden de bahsettiğimiz gibi read ve write alanlarına yazacağınız metod ya da değişkenler, özellik ile aynı tipte olmalıdır. Ve özellik tanımlanmadan önce bunların tanımlanması gerekir. Bu tanımlama kısmını örneğimizde göstermedik.</p><div
align="justify"><p>Şimdi aşağıdaki örneğe bakalım</p></div><div><pre>
<pre class="brush: delphi">TAraba = class
private
  FMarka: string;
  function GetMarka: string;
  procedure SetMarka(const Value: string);
public
  property Marka: string read GetMarka write SetMarka;
end;

implementation

function TAraba.GetMarka: string;
begin
  Result := FMarka;
end;

procedure TAraba.SetMarka(const Value: string);
begin
  if Value = &#039;Toyota&#039; then
  begin
    ShowMessage(&#039;Toyota markası kabul edilmedi!!&#039;);
  end
  else
    FMarka := Value;
    ShowMessage(&#039;Şuan ki Marka = &#039; + FMarka);
  end;
end;</pre></pre></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><p
align="justify">&ldquo;Marka&rdquo; isimli özelliğimizde read ve write metodlarında iki adet metod bulunmaktadır. Nesne tabanlı programlamada bu metodlara <strong>Getter</strong> ve <strong>Setter</strong> denilmektedir. Önceki örnekten farklı olarak burada hem read için hem de write için metod kullanıldı.</p><p
align="justify">Getter ve Setter metodlarının tanımlamasının illaki private alanda olmasına gerek yok. Ama tavsiye edilen tanımlama, private ve protected alanlarında yapılmasıdır. Eğer alt sınıflarda bu getter ve setter metodlarının üzerine yazmayı planlamıyorsanız, private kısmında bırakabilirsiniz.</p><p
align="justify">Örneğimizi incelediğinizde, Marka özelliğimizden bir değer &ldquo;okunmaya&rdquo; çalışıldığında GetMarka fonksiyonu çalışıyor. Ve bu fonksiyonun çıkış değeri Marka özelliğinin de çıkış değeri oluyor. Aynı şekilde Marka özelliğine bir değer atılmaya kalkıldığında, SetMarka prosedürüne değer parametre olarak yollanır. Bu örneğimizde yeni değer Value parametresi olarak SetMarka prosedürüne gelecektir.</p><p
align="justify">&ldquo;F&rdquo;, &ldquo;Get&rdquo; ve &ldquo;Set&rdquo; öneklerini kullanmanız sizin avantajınızadır. Siz bunlara farklı şeyler de verebilirsiniz. Ama bu önekleri kullanarak IDE editörü ile etkileşiminizi artırabilirsiniz. Mesela sadece alttaki tanımlamayı sınıfın public alanına yazın:</p><pre>
<pre class="brush: delphi">property BirOzellik: Integer read FBirOzellik write SetBirOzellik;</pre></pre><p
align="justify">Şimdi bu satırıda iken <font
face="Courier New">Ctrl+Shift+C</font> tuşlarına basın. Editör otomatik olarak read ve write kısmında yazılı olan değişken ya da metodu sizin yerinize tanımlayacaktır. Editörün otomatik olarak tanımlayabilmesi için değişken(ya da diğer tabir ile &ldquo;alan&rdquo;)&rsquo;ler için &ldquo;F&rdquo; öneki, Getter yani read fonksiyonları için &ldquo;Get&rdquo; öneki ve Setter yani write prosedürleri için &ldquo;Set&rdquo; önekini kullanmanız yeterlidir.</p><p
align="justify">Yukarıdaki örneği şu şekilde çalıştırın ve sonucu gözlemleyin:</p><div><pre>
<pre class="brush: delphi">var
  BirAraba: TAraba;
  ArabaninMarkasi: string;
begin
  BirAraba := TAraba;
  BirAraba.Marka = &#039;Subaru&#039;;
  BirAraba.Marka = &#039;Toyota&#039;;
  ArabaninMarkasi = BirAraba.Marka;
  ShowMessage(ArabaninMarkasi);
end;</pre></pre></div><div></div><div></div><div></div><div></div><p
align="justify">Özelliklerde son olarak değinmek istediğim nokta, sadece okunabilir olan ve sadece yazılabilir olan özelliklerdir.</p><p
align="justify">Sadece okunabilir olan bir özellik için, write alanını kaldırmamız yeterlidir. Aynı şekilde sadece yazılabilir olan bir özellik için de, read alanını kaldırmanız yeterlidir.</p><pre>
<pre class="brush: delphi">property ReadOnlyProp: Integer read FReadOnlyProp; // Sadece okunabilir
property ReadOnlyProp: Integer write FReadOnlyProp; // Sadece yazılabilir</pre></pre><div></div><div><h2>Türeme, Kalıtım ve Miras Alımı</h2></div><p
align="justify">Bundan önce bir sınıftan türetmeyi göstermiştik. Tak yapmamız gereken sınıf tanımlamasında ata sınıfı belirtmektir. Eğer belirtmezseniz, sınıfınız TObject sınıfından türeyecektir.</p><div><pre>
<pre class="brush: delphi">TCokOzelButton = class(TWinControl)
TCookDegisikResim = class(TImage)
TJanjanliLabel = class(TLabel)</pre></pre></div><div></div><div></div><div
align="justify"><p>gibi&#8230;</p></div><p
align="justify">Bildiğiniz kadarı ile, türettiğiniz ata sınıfına ait private alanı hariç tüm alanlardan faydalanabilirsiniz. Bu nesne özelliğine <u>kalıtım</u> diyoruz.</p><p
align="justify">Bir sınıftan türetme yaptığınız vakit, ata sınıfa ait belli bazı metodları tekrar tanımlamak isteyebilirsiniz. Ya da protected olan bazı özellikleri public ya da published yapmak isteyebilirsiniz. Bu durumda, bu özellik ya da metodu kalıtım yolu ile alıp tekrar tanımlamanız gerekmektedir. Metodlar için bu işleme, üzerine yazma(override) ya da inherit(miras alımı) denilmektedir.</p><div
align="justify"><p>Mesela iki adet sınıfımız olsun:</p></div><div><pre>
<pre class="brush: delphi">TAnchestorClass = class
protected
  procedure BirSeylerYap(Param1: string); virtual;
end;

TMyClass = class(TAnchestorClass)
public
  procedure BirSeylerYap(Param1: string, Param2: Integer); override;
end;

implementation

procedure TMyClass. BirSeylerYap(Param1: string, Param2: Integer);
begin
  //Ata sınıftaki metodu çağırmadan önce yapılacaklar.
  inherited BirSeylerYap(Param1);
  //Ata sınıftaki metod çağrıldıktan sonra yapılacaklar.
end;</pre></pre></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div
align="justify"><p>Burada dikkat etmemiz gereken üç kısım var.</p></div><p
align="justify">Birincisi, ata sınıfta tanımlayacağımız metodun üzerine yazılabilir olabilmesi için <font
face="Courier New"><strong>virtual</strong></font> ya da <strong><font
face="Courier New">dynamic</font></strong> tanımlıyoruz. Aksi halde metodumuz static olacaktır. Ama bu konuya fazla girmiyoruz. Bu kısımda tek söylemek istediğim şey virtual ile dynamic arasındaki farktır. Dynamic metodlar virtual metodlara nazaran daha<u> yavaş</u> çalışırlar ama hafıza kullanımı olarak virtual metodlardan daha <u>az</u> yer tutarlar. Şimdiki işletim sistemlerinde bu fark yok denecek kadar az olduğu için, genelde virtual metodlar kullanılır. Dynamic ve virtual metodların tarihi gelişmesini öğrenmek istiyorsanız ve ayrıntılı bilgi almak istiyorsanız <a
href="http://hallvards.blogspot.com/2006/04/dynamic-methods-and-inherited.html">buradan</a> ulaşabilirsiniz.</p><p
align="justify">İkinci olarak, çocuk sınıflarda üzerine yazımak istediğimiz ya da tekrar tanımlamak istrediğimiz metodun tanımlamasından sonra <font
face="Courier New"><strong>override</strong></font> alan tanımlayıcısını getiriyoruz. Örneğimizde gördüğünüz gibi ata sınıfa nazaran fazladan bir parametre daha eklenmiştir.</p><p
align="justify">&Uuml;çüncü olarak, çocuk sınıfımızda metodun kodlarında <font
face="Courier New"><strong>inherited</strong></font> ayrılmış kelimesi ile <u>ata sınıfın metodu</u>nu çağırıyoruz. <font
face="Courier New"><strong>inherited</strong></font> kelimesinden sonra metodun <u>ata sınıftaki tanımlanmış haline</u> göre metodu çağırıyoruz. Yukarıda örnekteki <strong><font
face="Courier New">inherited</font></strong> kısmı <font
face="Courier New">TAnchestorClass.BirSeylerYap(Param1)</font> gibi bir manaya gelmektedir.</p><p
align="justify">Eğer inherited ile ata sınıfın metodunu çağırmazsanız, BirSeylerYap metodu çağrıldığında sadece sizin metodunuz çalıştırılacaktır. Ata sınıfın metodu hiç bir zaman çalıştırılmayacaktır. Bunun için, ileride yapacağınız bileşenlerde, ata sınıfın bir metodunu override yaptığınızda bu noktaya dikkat ediniz. Mesela <font
face="Courier New">TPanel</font>&rsquo;den türeyen bir sınıfınızda Paint metodunu override yaptığınızda ve inherited ile <font
face="Courier New">TPanel</font>&rsquo;in Paint metodunu kendi metodunuz içinde bir yerde çağırmadığınızda, <font
face="Courier New">TPanel</font> ekrana çizilmeyecektir. Programın çökmesine bile sebebiyet verebilirsiniz.</p><p
align="justify">Ek olarak override kelimesini sadece virtual ve dynamic metodlarda kullanabiliyoruz. Static metodlarda override kelimesini kullanamazsınız.</p><p
align="justify">Aynen metodlar gibi constructor ve destructor&rsquo;lar da override edilebilir. Ve genelde constructor&rsquo;lar virtual ve destructor&rsquo;lar da static olarak tanımlanmışlardır. Aşağıdaki örneğe göz atalım:</p><div><pre>
<pre class="brush: delphi">TMyComponent = class(TComponent)
public
  constructor Create(AOwner: TComponent); override;
  destructor Destroy;
end;

implementation

constructor TMyComponent.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  // nesne oluşturulduktan sonraki işlemler
end;

destructor TMyComponent.Destroy;
begin
  //nesne yok edilmeden hemen önceki işlemler
  inherited;
end;</pre></pre></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><p
align="justify">Metodların inherit edilmesinden farklı değil, değil mi? Ama ata sınıfın constructor ve destructor&rsquo;ını nerede çağıracağınız önemlidir. Mesela Destroy &lsquo;da inherited kelimesinden sonraki kodlar çalıştırılmayacaktır. &Ccedil;ünkü ata nesnenin Destroy destructor&rsquo;ı nesneyi yok edecektir. Farkında iseniz ata nesnenin Destroy&rsquo;unda parametre olmadığından, sadece inherited; şeklinde kullandık.</p><p
align="justify">Son olarak bu konuda değinmek istediğim metodların ve özelliklerin kalıtım yolu ile görünürlüğünün değiştirilmesidir.</p><p
align="justify">Bir önceki örnekte göreceğiniz gibi TAnchestorClass sınıfında <font
face="Courier New"><strong>protected</strong></font> olan metod TMyClass çocuk sınıfında <font
face="Courier New"><strong>public</strong></font> olarak tanımlanmıştır. Yani ata sınıftan oluşturulan bir <u>nesne</u> BirSeylerYap metodunu göremezken, çocuk sınıfta bu public olduğu için, çocuk sınıftan oluşturulan bir nesne BirSeylerYap metodunu görüp erişebilecektir.</p><div
align="justify"><p>Aynı şekilde <u>protected olan bir özelliği</u> zahmetsiz bir şekilde görünür yani public yapabilirsiniz. Yani:</p></div><div><pre>
<pre class="brush: delphi">// Ata sınıf tanımlaması...
protected
  property BirOzellik: Integer read FBirOzellik write SetBirOzellik;

//&amp;Ccedil;ocukSınıf tanımlaması
public
  property BirOzellik;</pre></pre></div><div></div><div></div><div></div><div></div><div></div><p
align="justify">Görüldüğü gibi tekrar özelliğin read ve write metodlarını yazmamıza gerek kalmadan, ata sınıfta <u>gizli</u> olan bir özelliği çocuk sınıfta <u>görünür</u> hale çevirdik.</p><p
align="justify">Peki özellikler, inherit yapılamaz mı? Yapılabilir ama override kelimesi ile değil. Ata sınıftaki bir özelliği çocuk sınıfta tekrar tanımlamak istiyorsak:</p><div><pre>
<pre class="brush: delphi">//Ata sınıf tanımlaması
protected
  FColor: TColor;
  procedure SetColor(const Value: TColor);
  property Color: TColor read FColor write SetColor;

//&amp;Ccedil;ocuk sınıfı tanımlaması
protected
  FColor: TColor;
  procedure SetColor(const Value: TColor);
public
  property Color: TColor read FColor write SetColor;</pre></pre></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><p
align="justify">Peki bu bize ne kazandıracak? <u>Ata sınıfa ait bir özelliği</u> çocuk sınıfta da yönetmemize imkan sağlayacaktır. Ayrıca özelliğin getter ya da setter metodu çalıştırılmak istendiğinde, ata sınıfın getter ve setter&#8217;ı yerine çocuk sınıfın getter veya setter&#8217;ı çalıştırılacaktır. &Ccedil;ocuk sınıf içinde ata sınıfın SetColor metoduna erişmek için de <font
face="Courier New"><strong>inherited</strong></font> kelimesini kullanabiliriz. Yani ata sınıfa ait özelliğin getter ve setter&rsquo;ını <font
face="Courier New"><strong>inherited</strong></font> ile çağırabilirsiniz. Tabi ata sınıftaki setter&rsquo;ın protected ya da public olması kaydı ile.</p><p
align="justify">Buaraya kadar nesne tabanlı programlamanın bileşen yazımında en çok işimize yarayan kısımlarına değindik. Başka kaynaklar ile daha ayrıntılı bilgiler edinebilirsiniz. Eğer bunları nasıl ve nerede kullanacağımızı merak ediyorsanız sabredin. &Ccedil;ünkü yapacağımız çoğu işlem bu bilgiler üzerine olacaktır.</p><div><h1>Bileşenlerde Özellikler ve Event(<em>Olay</em>)&rsquo;lar</h1></div><p
align="justify">Sınıflarda özelliklerin nasıl tanımlandığını gördük. Bir bileşen sınıfında bazı durumlarda özellikler özel anlam taşırlar. IDE, bileşen sınıfımıza ait özellikleri değiştirip düzenleyebilmek için bu özellikleri tanıyabilmesi lazımdır. Aynı şekilde, bu özellikleri form&rsquo;a kaydedip daha sonra bu özelliği formdan tekrar okuyabilmesi gerekmektedir. Bu işlem sadece tasarım zamanında değil, çalışma zamanında da yapılmalıdır.</p><p
align="justify">IDE&rsquo;nin özelliklerimizi tanıyabilmesi için özellikleri, <font
face="Courier New"><strong>published</strong></font> alanında tanımlamamız gerekmektedir. Ayrıca özelliklerin kaydedilip tekrar yüklenebilmesi için kalıcılığının da sağlanması gerekmektedir.</p><p
align="justify">Basit veri tipleri için kalıcılık, IDE tarafından otomatik olarak sağlanır. Mesela <font
face="Courier New">Integer</font>, <strong><font
face="Courier New">string</font></strong>, <font
face="Courier New">Byte</font>, <font
face="Courier New">Boolean</font>, sıralı tipler bu tip basit tiplerdendir. Ve bazı daha kompleks tipler için de özel fonksiyonlar tanımlanmıştır. Mesela <font
face="Courier New">TImage</font> bileşeninde bulunan <font
face="Courier New">TPicture</font> verilerini okuyup yazabilmek için <font
face="Courier New">LoadFromStream</font> ve <font
face="Courier New">SaveToStream</font> gibi bazı metodlar mevcuttur. <font
face="Courier New">TMemo</font>&rsquo;da bulunan <font
face="Courier New">Lines</font> özelliği de bu tarz bir özelliktir. Kendi veri tiplerinizin kalıcılığının sağlanması, daha sonraki bölümlerde bahsedeceğimiz konulardandır. Şimdilik yapacağımız örnekler, hazır kalıcılığı sağlanmış olan kompleks tipler ile, basit veri tipleri ile ilgili olacaktır.</p><p
align="justify"><strong>Event (<em>Olay</em>)</strong></p><p
align="justify">Bir Event (<em>Olay</em>) ise bir çeşit özelliktir. Event&rsquo;ların tipi <u>metod işaretçileri</u>dir. Yani eğer bir özelliğin tipi <u>metod işaretçisi</u> ise bu özellik, event(olay) olarak bilinir.</p><p
align="justify">Metod İşaretçileri, <u>sınıf içinde bulunan</u> fonksiyon ve prosedürelerin işaretçilerini tutan değişkenlerdir. Normal fonksiyon ve prosedür işaretçilerinden farklı olarak metod işaretçilerinin tanımlanma şekli biraz değişiktir. Bir metod işaretçisi tanımlayabilmek için ilk başta metod işaretçisinin <u>tipini</u> tanımlamamız gerekmektedir. Ardından, bu tip ile oluşturulmuş herhangi bir <u>değişken</u>, aynen metod çağırır gibi çağrılabilir.</p><div
align="justify"><p>İlk olarak bir metod işaretçi tipi belirleyelim.</p></div><div><pre>
<pre class="brush: delphi">type
TMyEvent = procedure(Param1: string) of object;</pre></pre></div><div></div><p>Ardından bu metod işaretçi tipini kullanan bir event tanımlayalım</p><div><pre>
<pre class="brush: delphi">TMyClass = class
private
  FOnMyEvent: TMyEvent;
published
  property OnMyEvent: TMyEvent read FOnMyEvent write FOnMyEvent;
end;</pre></pre></div><div></div><div></div><div></div><div></div><p
align="justify">Artık <font
face="Courier New">OnMyEvent</font> adında yeni bir event&rsquo;ımız mevcut. Burada getter ve setter olarak girdiğimiz <font
face="Courier New">FOnMyEvent</font> değişkeni ise metod işaretçisidir. Daha sonradan bu sınıfımız içinde bir yerde bu metod işaretçisini çağırabiliriz.</p><div><pre>
<pre class="brush: delphi">if Assigned(FOnMyEvent) then
  FOnMyEvent(&#039;Param1 parametresi&#039;);</pre></pre></div><p>Bu işlemden sonra, <font
face="Courier New">FOnMyEvent</font>&rsquo;a <u>atanmış olan metod</u> çağırılacaktır. Mesela :</p><div><pre>
<pre class="brush: delphi">type
TForm1 = class(TForm)
  ....
  procedure MyObjectMyEvent(Param1: string);
  ....
end;

....

var
  MyObject: TMyClass;
begin
  MyObject := TMyClass.Create;
  MyObject.OnMyEvent := MyObjectMyEvent;
end;</pre></pre></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><p
align="justify">Yukarıdaki işlemde, <font
face="Times New Roman">MyObject</font> nesnesinin <font
face="Courier New">OnMyEvent</font> olayına Form1&rsquo;de bulunan <u>gerçek bir metod</u> atanmıştır. Böylece <font
face="Courier New">TMyClass</font> sınıfındaki <font
face="Courier New">FOnMyEvent</font> metod işaretçisi, Form1&rsquo;de bulunan <font
face="Courier New">MyObjectMyEvent</font> <u>gerçek metoduna</u> işaret eder olmuştur. <font
face="Courier New">TMyClass</font> içinde herhangi bir yerdeki <font
face="Courier New">FOnMyEvent()</font> çağırımı, Form1&rsquo;deki atadığımız metodu yani bu örneğimizde <font
face="Courier New">MyObjectMyEvent</font> metodunu çağıracaktır. Bu işleme <strong>Olay Tetikleme</strong> ya da <strong>Event Triggering</strong> denilmektedir.</p><p
align="justify">Mesela Form üzerine eklediğiniz bir <font
face="Courier New">TButton</font> bileşeninin <font
face="Courier New">OnClick</font> olayına çift tıklayın. IDE, otomatik olarak Form&rsquo;un sınıfı içinde <u>yeni bir metod</u> oluşturacaktır. Buraya bir kaç kod yazın ve kaydedip kapatın. Ardından Unit&rsquo;e ait &ldquo;dfm&rdquo; yada .net için &ldquo;nfm&rdquo; dosyasına notepad gibi bir programla baktığınızda aynen yukarıdaki örneğimizdeki gibi, Button&rsquo;nun OnClick olayına IDE&rsquo;nin oluşturduğu metoda eşitlendiğini göreceksiniz. <font
face="Courier New">TButton</font>, kendi içinde bunu <font
face="Courier New">FOnClick</font> gibi gizli bir metod işaretçisine bu metodu atayacaktır.</p><p
align="justify">İleride Event&rsquo;lar ile ilgili daha fazla örnek yapacağız. Şu an için bu kadar teorik bilgi yeterli diye düşünüyorum.</p><div><h1>Register İşlemi</h1></div><p
align="justify">Hatırlayacağınız gibi, makalenin başında bahsettiğimiz gibi, IDE&rsquo;nin bileşenimizi tanıyabilmesi için belli kriterler vardır. Bunlardan en birincisinin, bileşenin <font
face="Courier New">TComponent</font> ve alt sınıflardan türemesi gerektiğini gördük.</p><p
align="justify"><font
face="Courier New">TComponent</font> sınıfından türeyen bir sınıf oluşturduktan sonra, IDE&rsquo;nin bu bileşeni kullanabilmesi için <strong>kayıt</strong> ettirmeliyiz. Bunun için <strong><font
face="Courier New">Register</font></strong> prosedürü kullanılmaktadır. Basit bir <strong><font
face="Courier New">Register</font></strong> işlemi şu şekildedir.</p><div><pre>
<pre class="brush: delphi">procedure Register;

implementation

procedure Register;
begin
  RegisterComponents(&#039;Bileşen Kategorisi&#039;, [TMyComponent]);
end;</pre></pre></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><p
align="justify">IDE, bileşenimizin <u>paketini</u> kayıt ederken, otomatik olarak <strong><font
face="Courier New">Register</font></strong> prosedürünü çağıracaktır. Bunun içine yazdığımız <font
face="Courier New">RegisterComponents</font> prosedürü de sınıfımızı bileşen olarak kaydettirecektir. İlk parametre, bileşenin araç paletinde hangi kategoriye gireceğidir. İkinci parametre ise array tipinde, kaydettirilecek olan bileşen sınıflarıdır. Bu parametreye <font
face="Courier New">[TBilesen1, TBilesen2]</font> şeklinde girerek birden fazla kayıt yaptırabilirsiniz.</p><div><h1>İlk Bileşenimizi Yazalım</h1></div><p
align="justify">Bu kadar bilgiden sonra artık ilk bileşenimizi yazabiliriz. Bileşenimiz, <font
face="Courier New">Caption</font> özelliğine girilen değerin geçerli bir sayı olmaması durumunda bir hata gösteren ve değeri kaydetmeyen bir bileşen hazırlayalım.</p><p
align="justify">Bunun için ata sınıf olarak <font
face="Courier New">TLabel</font> sınıfını seçiyoruz. Ve bu sınıfa ait <font
face="Courier New">Caption</font> özelliğinin <u>üzerine yazalım</u>. Bileşenimiz şu şekilde olacaktır.</p><div><pre>
<pre class="brush: delphi">interface

uses
  SysUtils, Classes, Controls, StdCtrls, Dialogs;

type
  TNumberLabel = class(TLabel)
  private
    function GetCaption: TCaption;
    procedure SetCaption(const Value: TCaption);
  protected
  public
    constructor Create(AOwner: TComponent); override;
  published
    property Caption: TCaption read GetCaption write SetCaption;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents(&#039;Samples&#039;, [TNumberLabel]);
end;

{ TNumberLabel }

constructor TNumberLabel.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  Caption := &#039;0&#039;;
end;

function TNumberLabel.GetCaption: TCaption;
begin
  Result := inherited Caption;
end;

procedure TNumberLabel.SetCaption(const Value: TCaption);
var
  E, Number: Integer;
begin
  Val(Value, Number, E);
  if E &lt;&gt; 0 then
    ShowMessage(&#039;Bir sayı girmelisiniz!&#039;)
  else
    inherited Caption := Value;
end;</pre></pre></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><p
align="justify">Bu bileşenin nasıl kurulacağına sonra değineceğiz. Şimdi kodları açıklayalım.</p><p
align="justify">Sınıf tanımlamasına baktığımızda bir adet constructor, bir adet property ve bu property&rsquo;e ait olan setter ve getter&rsquo;ı görüyoruz. Caption özelliği burada gördüğünüz gibi ata sınıfın Caption özelliğinin üzerine yazılmış durumda. Ata sınıfın bir özelliğine ya da bir metoduna ulaşmak için &ldquo;<font
face="Courier New"><strong>inherited</strong></font>&rdquo; kelimesini kullandığımızı görmüştük.</p><p
align="justify">Bu özelliğin <font
face="Courier New">GetCaption</font> getter metoduna baktığımızda, çıkış olarak ata sınıfın <font
face="Courier New">Caption</font> özelliğinin çıktı olarak verildiğini görüyoruz. Aynı şekilde <font
face="Courier New">SetCaption</font> setter metodunda ise Caption&rsquo;a atanan değerin geçerli bir sayı olup olmadığını kontrol ediyoruz. Eğer geçerli değilse hata mesajını gösteriyoruz, eğer geçerli bir sayı ise, ata sınıfın Caption özelliğine bu yeni değeri atıyoruz.</p><p
align="justify">Bildiğiniz gibi Delphi, forma yeni eklenen bir bileşenin Caption ya da Text özelliğini, bileşenin ismi olarak belirliyor. Ve bu bileşeni yeni eklediğinizde Caption olarak &ldquo;NumberLabel1&rdquo; gibi bir şey atayacak. Ki bu, geçerli bir sayı değildir. Bu yüzden ilk değer olarak Caption özelliğine bir sayı atamalıyız. Bunun gibi ilk değerleri bileşenin Create constructor&rsquo;ında vermeliyiz. Zaten Create constructor&rsquo;ına baktığınızda anlayacaksınız. Ayrıca hatırlatmak gerekirse, buradaki constructor <strong><font
face="Courier New">virtual</font></strong> olarak tanımlanmıştır. Bu yüzden <font
face="Courier New"><strong>override;</strong></font> kelimesini kullanmayı unutmuyoruz.</p><div><h2>Bileşen Kurulumu</h2></div><p
align="justify">Aslında bileşen yazımı ile alakası olmasa da, çoğu zaman yeni bileşen yazanlar için kafa karıştırıcı bir konudur. Ama yeni bir bileşeni kurmak için gereken şartları sağladığınızda hiç bir sorun ile karşılaşmayacaksınız.</p><p
align="justify">Her bileşen mutlaka bir paket içinde olmalıdır. Delphi 7 ve öncesinde, hazır tanımlanmış olan bir paket bulunuyordu. Ve paket yerine pas uzantılı bir bileşeni kurmak istediğinizde, IDE bunu hazır olan bu paket içine otomatik olarak atıp orada derliyordu. Ama Delphi 8 ve daha sonraki versiyonlarda bu paketten vazgeçildi.</p><p
align="justify">Bir VCL bileşeni kurabilmeniz için ilk başta eğer paket&rsquo;i yok ise bir paket oluşturuyoruz. Bunun için Menü&rsquo;den File/New/Other ile açılan pencereden Package&rsquo;i bulup seçiyoruz. Project Manager bölümünde boş bir paket oluşturulmuş durumda. Contains kısmında paketin içinde bulunacak olan unit&rsquo;ler, ve Requires kısmında ise bu paketin ihtiyaç duyduğu diğer paketler bulunacaktır. Contains kısmına sağ tuş ile tıklayıp &ldquo;Add New&rdquo; ile yeni bir Unit ekleyelim. Ve yukarıdaki TNumberLabel bileşenini buraya yapıştırıp paketle birlikte bir klasöre kaydedelim. Ardından bu paketi Shift+F9 ile derleyelim. Eğer çıkış için bir klasör belirlememiş iseniz, My Documents/Borland Studio Projects/Bpl altında bu paketin derlenmiş dosyasını bpl dosyası şeklinde görebilirsiniz. Bu arada, Bpl dosyaları bir çeşit Dll&rsquo;dir.</p><p
align="justify">Derleme işleminden sonra Menüden Tools/Options ile açılan pencereden Library &ndash; Win32 kısmını bulalım. &ldquo;Library Path&rdquo; altına bileşenimizin pas dosyasını kaydettiğimiz klasörü ekleyelim.</p><p
align="justify">En son olarak Menüden &ldquo;Component/Install Packages&#8230;&rdquo; ile derlenmiş olan bpl dosyasını bulup bileşenimizi kuralım. Bileşenimiz <strong><font
face="Courier New">Register</font></strong> prosedüründe belirttiğimiz kategori altına kaydedilmiş olmalıdır.</p><p
align="justify">VCL.NET için de işlemler bu şekildedir. Tek fark, derlediğiniz paket bir Bpl değil, Dll uzantılı bir .NET assembly&rsquo;si olacaktır. Daha sonra bu dll dosyasını Component/Install .NET Component altından VCL Components kategorisi altına ekleyebilirsiniz.</p><p
align="justify">Bu bölüm buraya kadar yeterli. Buraya kadar öğrendiklerimizi bir bir gözden geçirelim, atlamayalım. &Ccedil;ünkü bu bilgiler, hem bileşen yazımının temelini oluşturmakta, hem nesne programlamanın temelini oluşturmakta hem de Delphi&rsquo;nin çalışma mantığını göstererek, Delphi programlamada neyin nasıl gerçekleştiği noktasında bizlere fikir vermektedir.</p><div
align="justify"><p>Fikir, eleştiri ve yorumlarınızı bekliyorum.</p></div><div>Fatih Tolga Ata &copy; 2007</p><p><a
href="http://www.diyezon.com/?p=40">Bölüm 1</a> &#8211; <a
href="http://www.diyezon.com/?p=41">Bölüm 2</a> &#8211; <a
href="http://www.diyezon.com/?p=42">Bölüm 3</a></p></div> ]]></content:encoded> <wfw:commentRss>http://www.diyezon.com/bilesen-yazim-klavuzu-1/feed/</wfw:commentRss> <slash:comments>9</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/5 queries in 0.006 seconds using memcached
Object Caching 627/627 objects using memcached

Served from: www.diyezon.com @ 2012-02-08 11:30:06 -->
