Makale Özeti

Bu makale standart operatörleri overload edip kendi istediğimiz şekilde davranmalarını nasıl sağlayacağımıza değinmektedir.

Makale

        Merhabalar,

 

 

        Bu makalemde birlikte operator overloading'i inceleyeceğiz. Temel bilgilere sahip olduktan sonra yazılmış bir örnek üzerinden adım adım ilerleyerek konuyu daha rahat kavrayabileceğiz. Peki nedir bu Operator Overloading, nerelerde kullanılır, ne gibi avantajlar sağlar?. Şimdi bu soruların cevaplarını bulmaya çalışalım.

 

        Tüm unary veya binary operatörlerin default tanımlanmış ve bizim programlarımızda kullandığımız implemantasyonları vardır. Operator Overloading bu default implemantasyonları kendi yazdığımız özel bir tipe,yapıya veya class'a göre yeniden yazmammızı ve tanımladığımız nesneler arasında bu operatörlerle özel işlemler yapmamızı sağlar. Ancak C# da tüm operatorler overload edilememektedir. Şimdi operatörleri sınıflandıralım ve hangilerinin overload edilebildiğini inceleyelim.

 

Operatörler

Sınıflandırma

Overload Edilebilirlik

+, -, *, /, %, &, |, <<, >>

Binary Operatörler

Tümü overload edilebilir

+, -, !,  ~, ++, --, true, false

Unary Operatörler

Tümü overload edilebilir

==, !=, <, >, <= , >=

Relational (İlişkisel) Operatörler

Çiftler halinde overload edilebilir.

&&, ||

Logical Operatörler

Overload Edilemez.

()

Conversation Operatörler

Overload Edilemez.

+=, -=, *=, /=, %=

Bileşik Atama Operatörleri

Overload Edilebilir. Binary operatörlerdeki
değişiklikler bu operatörlere yansır.

=, . , ?:, ->, new, is, as, sizeof

 

Overload Edilemez.

 

    Operator Overload etmek için yazacağımız fonksiyona ait bazı kesin kurallar vardır. Bu kurallar fonksiyonun veya methodun public ve static tanımlanması,sadece value argument alabilmesi, ref ve out parametrelerinin desteklenmemesi ve argumanlardan en az birinin kullanıcı tanımlı tipte (örn. class) olmasıdır. Bu durumda genel bir syntax çıkartacak olursak bu syntax aşağıdaki gibi olacaktır.

 

        public static donusTipi operator operatorTipi (arguman listesi)

 

        Unary operatörlerin overloadında syntax public static donusTipi operator operatorTipi (tip t) { } şeklindedir. +, ~, ! gibi unary operatörler için dönüş tipi void dışında herhangi bir tip olabilirken ++,-- gibi fonksiyonlarda arguman olarak alınan tip ile aynı tipte olmalıdır. Ayrıca önemli bir nokta ise true operatörü overload edildiği zaman false operatörününde overload edilmesi gerekemesidir. Bu operatörlerden sadece biri overload edildiğinde hata verecek ve proje build edilmeyecektir.

 

        Binary operatörlerin overloadında syntax public static donusTipi operator operatorTipi (Tip1 t1, Tip2 t2){ } şekilndedir. Overload edilmiş bir binary operatör 2 tane arguman almalıdır ve bunlardan biri mutlaka tanımlandığı class'ın tipiyle aynı olmalıdır. Dönüş tipi ise void dışında herhangi bir tip olabilir. ==, !=, <, >, <=, >= gibi binary operatörler sadece çiftler şeklinde overload edilebilir. Ayrıca bir binary matematiksel operatör overload edildiğinde buna bağlı atama operatörüde otomatikman overload edilir. (Örneğin - ve -=)

 

        Operator overload genellikle matris işlemleri, karmaşık sayılarla işlemler gibi konularda kullanılır. Bu örnekte daha basite indirgenmiş bir uygulama ile bu konuyu inceğiz. Eminmki bu makaleden sonra benzer örnekleri sizde geliştirebileceksiniz. Örneğimize başlayalım.

 

        Markette dolaşırken 2 tane bayan gördüğümüzü düşünelim ve sepetlerinde elma ve armutlar olsun. Burada sepet bizim classımız, içinde bulunan elma ve armutlar ise propertylerimiz olcak. Cevap bulmaya çalışacağımız sorular ise sepetlerin toplamı nedir?(elma ve armut sayılarının ayrı ayrı toplanması gerek), Sepetlerin farkı nedir?,Sepetler eşitmidir?. İlk sepete bir elma bir armut atarsa kaç elma kaç armut olur gibi sorulardır. Şimdi kodlamaya başlayalım ve Sepetimizi yaratalım.

 

 

using System;

namespace OperatorOverloading

{

      public class Sepetim

      {

            private int mElmaSayisi;

            private int mArmutSayisi;

 

            public Sepetim()

            {

            }

            public Sepetim(int pElmaSayisi,int pArmutSayisi)

            {

                  this.ElmaSayisi=pElmaSayisi;

                  this.ArmutSayisi=pArmutSayisi;

            }

            public int ElmaSayisi{

                  get

                  {

                        return mElmaSayisi;

                  }

                  set

                  {

                        mElmaSayisi = value;

                }

            }

            public int ArmutSayisi

            {

                  get

                  {

                        return mArmutSayisi;

                  }

                  set

                  {

                        mArmutSayisi = value;

                  }

            }

 

        Bu kısımda classımızı yaratıp ona ait propertyleri ve enCapsulationları oluşturuyoruz. Yani sepetimizde bulunacak elma veya armut sayısını artık belirleyebilir veya mevcut olan değeri istediğimiz zamanda öğrenebiliriz. Şimdi unary operatörlerimizden kullanacaklarımızı overload edelim.

 

 

            public static Sepetim operator - (Sepetim pSepetim)

            {

                  return new Sepetim(-pSepetim.ElmaSayisi,-pSepetim.ArmutSayisi);

            }

            public static Sepetim operator ++ (Sepetim pSepetim1)

            {

                  return new Sepetim(pSepetim1.ElmaSayisi +1,pSepetim1.ArmutSayisi+1);

            }

            public static Sepetim operator -- (Sepetim pSepetim1)

            {

                  return new Sepetim(pSepetim1.ElmaSayisi -1,pSepetim1.ArmutSayisi-1);

            }

 

Bu kısımda kendi sınıfımıza ait unary operatörlerimizden -,++,-- yı overload ediyoruz. Sepetimizi parametre olarak alan bu fonksiyonlarda sepetimizin içindeki elma ve armut sayılarında değişiklik yapılıp sepetimize benzer bir sepet geri döndürülüyor. - operatöründe sepette bulunan elma ve armut sayısı negatifize olurken ++ da bir artmakta ve -- de bir azalmaktadır. Şimdi binary operatörlerimizden kullanacaklarımızı overload edelim.

 

public static Sepetim operator + (Sepetim pSepetim1,Sepetim pSepetim2)

            {

                  return new Sepetim(pSepetim1.ElmaSayisi + pSepetim2.ElmaSayisi, pSepetim1.ArmutSayisi+pSepetim2.ArmutSayisi);

            }

            public static Sepetim operator - (Sepetim pSepetim1,Sepetim pSepetim2)

            {

                  return new Sepetim(pSepetim1.ElmaSayisi - pSepetim2.ElmaSayisi,pSepetim1.ArmutSayisi-pSepetim2.ArmutSayisi);

            }

            public static bool operator ==(Sepetim pSepetim1,Sepetim pSepetim2)

            {

                  if(pSepetim1.ElmaSayisi==pSepetim2.ElmaSayisi && pSepetim1.ArmutSayisi==pSepetim2.ArmutSayisi)

                  {

                        return true;

                  }

                  else

                  {

                        return false;

                  }

            }

            public static bool operator !=(Sepetim pSepetim1,Sepetim pSepetim2)

            {

                  if(pSepetim1.ElmaSayisi!=pSepetim2.ElmaSayisi || pSepetim1.ArmutSayisi!=pSepetim2.ArmutSayisi)

                  {

                        return true;

                  }

                  else

                  {

                        return false;

                  }

            }

 

Bu kısımda ise classımıza ait binary operatörlerden +,-,= = ve ! = i overload ediyoruz. Bu kısımda ise artık fonksiyonlarımız iki tane sepet alıp bunları bir sepette birleştirmek,farklarını anlamak veya eşitliğini kontrol etmek gibi işlemler yapıyor. Bu fonksiyonlarda geri dönüş tipi herhangi bir değişken olabilmektedir. Unutmamalıyızki = = 'i overload ettiğimiz zaman != 'de overload etmeliyiz. ve aşağıda yer alan iki metoduda (Equals,GetHashCode) yazmalıyız.

 

public override bool Equals(object obj)

            {

                  return base.Equals (obj);

            }

            public override int GetHashCode()

            {

                  return base.GetHashCode ();

            }

 

Bu iki fonksiyonuda yazdıktan sonra sırada bir çift olarak bulunana > ve < operatörlerini override etmek var.

 

            public static bool operator >(Sepetim pSepetim1,Sepetim pSepetim2)

            {

                  if (pSepetim1.ElmaSayisi>pSepetim2.ElmaSayisi || pSepetim1.ArmutSayisi>pSepetim2.ArmutSayisi)

                  {

                        return true;

                  }

                  else

                  {

                        return false;

                  }

            }

            public static bool operator <(Sepetim pSepetim1,Sepetim pSepetim2)

            {

                  if (pSepetim1.ElmaSayisi>pSepetim2.ElmaSayisi || pSepetim1.ArmutSayisi>pSepetim2.ArmutSayisi)

                  {

                        return false;

                  }

                  else

                  {

                        return true;

                  }

            }

      }

}

 

Burada > operatörümüzü yazdıktan sonra < operatörümüzün içine uzun uzun yazmaktansa  return ! pSepetim1>pSepetim2; şeklindeki kısa bir cümle ile daha genel bir yapı elde edebilirdik ama şu an için performansı düşündüğümüzden bu yöntemle ilerledik. Bu yöntemlerde herhangi bir propertynin diğerinden büyük veya küçük olması daha büyük veya daha küçük diyebilmemiz için yeterlidir. Buradaki mantık sadece uygulama örneği amaçlı olduğundan çokta sağlıklı olmasa bize eminimki sizler bu konularda daha başarılı fonksiyonlar yazabileceksiniz.

Bu noktada artık classımızı ve overload edebileceğimiz operatörlerimizi bitirdik ve bu classı kullanacak örnek bir uygulama yazıp bunun üzerinden operatörlerimizin çalıştığının ispatını yapmalıyız. Form dizaynımız ve dizayndaki butonlara ait kodlar aşağıdaki gibi olacaktır

 

 

 

Şimdi formumuzda bulunan button ları ve yaptıkları işlemleri inceleyelim.

 

private void btnTopla_Click(object sender, System.EventArgs e)

            {

                  Sepetim iSepetim1=new Sepetim(Convert.ToInt32(txtSepet1ElmaSayisi.Text),Convert.ToInt32(txtSepet1ArmutSayisi.Text));

                  Sepetim iSepetim2=new Sepetim(Convert.ToInt32(txtSepet2ElmaSayisi.Text),Convert.ToInt32(txtSepet2ArmutSayisi.Text));

                  Sepetim iSepetim3=new Sepetim();

                  iSepetim3=iSepetim1 + iSepetim2;

                  txtSonucElmaSayisi.Text=iSepetim3.ElmaSayisi.ToString();

                  txtSonucArmutSayisi.Text=iSepetim3.ArmutSayisi.ToString();

            }

 

            private void btnCikart_Click(object sender, System.EventArgs e)

            {

                  Sepetim iSepetim1=new Sepetim(Convert.ToInt32(txtSepet1ElmaSayisi.Text),Convert.ToInt32(txtSepet1ArmutSayisi.Text));

                  Sepetim iSepetim2=new Sepetim(Convert.ToInt32(txtSepet2ElmaSayisi.Text),Convert.ToInt32(txtSepet2ArmutSayisi.Text));

                  Sepetim iSepetim3=new Sepetim();

                  iSepetim3=iSepetim1 - iSepetim2;

                  txtSonucElmaSayisi.Text=iSepetim3.ElmaSayisi.ToString();

                  txtSonucArmutSayisi.Text=iSepetim3.ArmutSayisi.ToString();

            }

 

            private void btnBirEkle_Click(object sender, System.EventArgs e)

            {

                  Sepetim iSepetim1=new Sepetim(Convert.ToInt32(txtSepet1ElmaSayisi.Text),Convert.ToInt32(txtSepet1ArmutSayisi.Text));

                  Sepetim iSepetim3= new Sepetim();

                  iSepetim1++;

                  iSepetim3=iSepetim1;

                  txtSonucElmaSayisi.Text=iSepetim3.ElmaSayisi.ToString();

                  txtSonucArmutSayisi.Text=iSepetim3.ArmutSayisi.ToString();

            }

 

            private void btnBirCikart_Click(object sender, System.EventArgs e)

            {

                  Sepetim iSepetim1=new Sepetim(Convert.ToInt32(txtSepet1ElmaSayisi.Text),Convert.ToInt32(txtSepet1ArmutSayisi.Text));

                  Sepetim iSepetim3= new Sepetim();

                  iSepetim1--;

                  iSepetim3=iSepetim1;

                  txtSonucElmaSayisi.Text=iSepetim3.ElmaSayisi.ToString();

                  txtSonucArmutSayisi.Text=iSepetim3.ArmutSayisi.ToString();

            }

 

            private void btnEsitmi_Click(object sender, System.EventArgs e)

            {

                  Sepetim iSepetim1=new Sepetim(Convert.ToInt32(txtSepet1ElmaSayisi.Text),Convert.ToInt32(txtSepet1ArmutSayisi.Text));

                  Sepetim iSepetim2=new Sepetim(Convert.ToInt32(txtSepet2ElmaSayisi.Text),Convert.ToInt32(txtSepet2ArmutSayisi.Text));

                  if (iSepetim1==iSepetim2)

                  {

                        MessageBox.Show("Esit");

                  }

                  else

                  {

                        MessageBox.Show("Esit Degil");

                  }

            }

 

            private void Form1_Load(object sender, System.EventArgs e)

            {

           

            }

 

            private void btnBuyukmu_Click(object sender, System.EventArgs e)

            {

                  Sepetim iSepetim1=new Sepetim(Convert.ToInt32(txtSepet1ElmaSayisi.Text),Convert.ToInt32(txtSepet1ArmutSayisi.Text));

                  Sepetim iSepetim2=new Sepetim(Convert.ToInt32(txtSepet2ElmaSayisi.Text),Convert.ToInt32(txtSepet2ArmutSayisi.Text));

                  if (iSepetim1>iSepetim2)

                  {

                        MessageBox.Show("Buyuk");

                  }

                  else

                  {

                        MessageBox.Show("Buyuk Degil");

                  }

            }

 

            private void btnKucukmu_Click(object sender, System.EventArgs e)

            {

                  Sepetim iSepetim1=new Sepetim(Convert.ToInt32(txtSepet1ElmaSayisi.Text),Convert.ToInt32(txtSepet1ArmutSayisi.Text));

                  Sepetim iSepetim2=new Sepetim(Convert.ToInt32(txtSepet2ElmaSayisi.Text),Convert.ToInt32(txtSepet2ArmutSayisi.Text));

                  if (iSepetim1<iSepetim2)

                  {

                        MessageBox.Show("Kucuk");

                  }

                  else

                  {

                        MessageBox.Show("Kucuk Degil");

                  }

            }

 

            private void btnNegatifize_Click(object sender, System.EventArgs e)

            {

                  Sepetim iSepetim1=new Sepetim(Convert.ToInt32(txtSepet1ElmaSayisi.Text),Convert.ToInt32(txtSepet1ArmutSayisi.Text));

                  Sepetim iSepetim3=new Sepetim();

                  iSepetim3=-iSepetim1;

                  txtSonucElmaSayisi.Text=iSepetim3.ElmaSayisi.ToString();

                  txtSonucArmutSayisi.Text=iSepetim3.ArmutSayisi.ToString();

            }


Kodlar uzun gibi gözüksede bu kodlarda yapılanlar sadece kendi sepetlerimizi yaratmak ve bazı yerlerde sepetlerimizi yaratırken sepetlerimizin içine elma ve armutlarımızı koymaktan ibarettir.
Bu makalemde verdiğim örnekte hata yakalama fonksiyonları örnek makaleyi tamamlayıcı yapıda olduğu için kullanılmamıştır.

Tamer ÖZ

oztamer@hotmail.com
tamer.oz@yazgelistir.com
oztamer@hotmail.com
Örnek Kodlar