Friday, December 14, 2012

Arayüzlerin (Interface) Kullanılması (c#)


 .NET sınıfı kütüphanesinde de birçok arayüz bulunmaktadır. Her arayüz çeşitli amaçlar için yazılmıştır. Örneğin System isim alanında bulunan IDisposable arayüzü gereksiz nesne toplayıcısı (garbage collector) için gerekli olabilecek Dispose() metodunun uygulanmasını zorlar. Aynı şekilde System.Collections isim alanında bulunan IEnumarable arayüzü tanımladığımız sınıfların foreach döngü yapısı ile kullanabilmesini sağlar. IEnumarable arayüzü içindeki metotlar ilgili sınıf tarafından uygulanırsa tanımlanan bu sınıf foreach döngüsü ile kullanılabilir. Çünkü foreach döngüsü çalıştırılmaya başlanınca foreach bloğunda kullanılan sınıfn IEnurable arayüzünü uygulayıp uygulamadığını kontol edilir. Eğer bu arayüz uygulanmış ise IEnumarable arayüzündeki metotlar kullanılarak foreach döngüsü işletilir.Bu konumuzda IEnumarable arayüzünün kullanımına bir örnek vereceğiz.

IEnumarable arayüzünü uygulayan bir sınıf foreach döngü yapısı ile kullanılabildiğini söylemiştik. Tabi foreach döngü yapısı ile kullanabileceğimiz bir sınıfın yapısında dizi ya da daha sonra göreceğimiz koleksiyon tabanlı bir yapının bulunması mantıklı olur.


using System;
using System.Collections;

class Koleksiyon : IEnumerable
{
    int[] Dizi;
    public Koleksiyon(int[] dizi)
    {
        this.Dizi = dizi;
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return new ENumaralandirma(this);
    }

    class ENumaralandirma : IEnumerator
    {
        int indeks;
        Koleksiyon koleksiyon;

        public ENumaralandirma(Koleksiyon koleksiyon)
        {
            this.koleksiyon = koleksiyon;
            indeks = -1;
        }

        public void Reset()
        {
            indeks = -1;
        }
        public bool MoveNext()
        {
            indeks++;

            if (indeks < koleksiyon.Dizi.Length)
                return true;
            else
                return false;
        }

        object IEnumerator.Current
        {
            get
            {
                return (koleksiyon.Dizi[indeks]);
            }
        }
    }
}

public class MainMetodu
{
    public static void Main()
    {
        int[] dizi = {1,2,3,8,6,9,7};

        Koleksiyon k= new Koleksiyon(dizi);

        foreach(int i in k)
            Console.Write(i + " ");

        Console.ReadLine();
    }
}





Bu programı derlediğimizde ekrana

1 2 3 8 6 9 7

yazıldığını göreceğiz.

Programda neler olup bittiğine göz atmak gerekirse, Koleksiyon isimli bir sınıfın yapısındaki Dizinin eleman değerlerini foreach döngüsü ile elde etmek için Koleksiyon sınıfı System.Collections isim alanında bulunan IEnumarable arayüzünü uyguluyor. Dolayısıyla IEnumarable arayüzündeki bütün metotları uygulamalıdır. IEnumerable arayüzünde sadece

IEnumerator GetEnumerator();

metodu ile bildirilmiştir. Bu metot dizinin içerisinde dolaşmak için gerekli olan IEnumerator referansına geri dönmektedir. Bu yüzden bu metot aşağıdaki gibi yazılmıştır.

IEnumerator IEnumerable.GetEnumerator()
{
  return new Enumaralandırma(this);
}

GetEnumerator() metodunun geri dönüş değeri için IEnumerator arayüzünden türetilmiş IEnumaralandırma sınıfı bildirilmiştir. IEnumerator arayüzündeki metot ve özellikler Koleksiyon nesnesi içindeki dizinin elemanlarına erişmek için kullanılacaktır. IEnumerator arayüzünde bulunan üye elemanlar aşağıdaki gibidir.

object Current{
get;
}

bool MoveNext();

Void Reset();

Bu iç elemanında IENumaralandırma sınıfında bildirilmesi gerekir. Current özelliği koleksiyon nesnesinin herhangi bir andaki değerini gösterir. Sade get bloğunu bildirmek yeterlidir. MoveNext() metodu dizi koleksiyon dizisi içinde bir sonraki elemana geçmek için kullanılır. Eğer bir sonraki elemana geçilemiyorsa false deperini geri döner. Reset() metodu ise koleksiyon dizisini herhangi bir andaki değerini ilk elemandan önceki elemana çeker. Yani dizinin indeksi -1 olur.

IEnumaralandırma sınıfının bir tane yapıcı metodu vardır. Bu yapıcı metot ile üzerinde işlem yapılacak Koleksiyon nesnesi alınmaktadır. Yapıcı metot ile aynı zamanda ENumarandırma sınıfındaki indeks değişkenide -1 değerine çekiliyor. Reset() metodunda ise indeks değişkeni bir artırılıyor. Eğer indeks değişkeninin  yeni değeri dizinin boyutundan büyükse false değerini geri dönmektedir. Current özelliğinin object olduğuna dikkat edin. Eper bu özellik object türünden olmasaydı mğmkğn olabilecek tür dönüşümlerini hesaba katmazsak bütün işlemleri sadece Current özelliği ile aynı türden olan diziler üzerinde yapabilirdik.

Açık (Explict) Arayüz Uygulama


C# dilinde arayüzleri uygulamanın bir yolu daha vardır. Explicit Interface Implementation. Bu yöntem daha önce bahsedilen yöntemlerin aşağıdaki kısımlarından kaynaklanmaktadır.

- Açık arayüz uygulama yöntemi ile istenirse türeyen sınıflarda arayüzde bulunan üye elemanlar açık bir şekilde nesneler tarafından erişilemez hale getirilebilir. İlgili üye elemanlarına sadece arayüz referansları ile erişilmesi sağlanır.

- Birden çok arayüz uygulandığı durumlarda eğer aynı isimli üye elemanlar varsa isim çakışmasının önüne bu yöntemle geçilebilir.

Açık arayüz uygulaması yapmak için arayüzün üye elemanları arayüz isimleri ile beraber belirtilir. Aşağıda buna bir örnek verilmiştir.

using System;
using System.Collections.Generic;
using System.Text;

namespace explicitinterfaceimplemetantion
{
  class Program
  {
     static void Main(string[] args)
     {
        Kedi k= new Kedi();
       
        ((IMEmeli).k).Konus();
     }
  }

interface IMemeli
{
   void Konus();
}

class Kedi : IMemeli
 {
   void IMemeli.Konus()
   {
      Console.WriteLine("miyav");
   }
 }
}

Yukarıdaki örnekte de görüldüğü üzere Konus() metodunun çağrılabilmesi için IMemeli arayüzü referansına çevrilmesi gerekiyor. Direkt Kedi nesneleri üzerinden Konus() metodu çağrılamayacaktır. Böylece sınıf nesneleri için arayüz üye elemanları private gibi davranmaktadır. Normal yöntemle bunu yapmak mümkün değildir.

Wednesday, December 12, 2012

Arayüz (Interface) Referansları (c#)


Arayüzler ile referans oluşturulabilir. Bir arayüz referansı tek başına bir anlam ifade etmez. Ancak arayüz
referanslarına kendisini uygulayan herhangi bir sınıf nesnesinin referansı atanabilir. Bu durumda arayüz
referansı ile arayüzde bulunan metot ya da özellikler hangi sınıf referansı tutuluyorsa o sınıf türünden bir
nesne için çağırılabilir.
Bu özelliğine örnek vermek gerekirse aşağıda ArayuzRef arayüzünü uygulayan iki sınıfın bildirimini görüyoruz.
Main() metodu içinde ise ArayuzRef referansına bu iki sınıfın nesne referanslarının nasıl aktarıldığını ve bu
referans üzerinden sınıflardaki metotların nasıl çağrıldığını görüyoruz.

using system;

interface ArayuzRef
{
  void metot1();
}

class Sinif1 : ArayuzRef
{
  puplic void metot1(){
  Console.WriteLine("Ben Sinif1'in metoduyum");
  }
}

class Sinif2 : ArayuzRef
{
  puplic void metot1(){
  Console.WriteLine("Ben Sinif2'nin metoduyum");
}

puplic class MainMetodu
{
  puplic static void Main()
  {
    ArayuzRef a;

Sinif1 sinif1 = new Sinif1();
Sinif2 sinif2 = new Sinif2();

a = sinif1;
a.metot1();

a = sinif2;
a.metot1();
   }
}

Programı derleyip çalıştırdığımızda ekrana

Ben Sinif1'in metoduyum
Ben Sinif2'nin metoduyum

yazacaktır. Arayüzlerdeki referans aktarma işlemi ile kalıtımda gördüğümüz temel sınıf referansına türeyen sınıf referansı aktarma işlemi ile aynıdır.

Monday, December 10, 2012

Arayüzlerin (Interface) Uygulanması (c#)


 Şimdi bir sınıfın belirlediğimiz bir arayüzün nasıl uygulandığını inceleyeceğiz.
Arayüzlerin uygulanması, sınıfların türetilmesi ile aynı şekilde yapılır. Arayüz uygulamada, arayüzler türetmedeki temel sınıf yerine geçer. Buna göre IArayüz'ü uygulayan Sayılar sınıfı aşağıdaki gibi bildirilir.

class Sayılar : Iarayuz
{
  //uygulanacak elemanlar
}

Sayılar sınıfı bu şekilde IArayuz'den türetildiğinde IArayuz'deki bütün üye elemanları uygulanmalıdır.

Buna göre Sayılar sınıfı IArayuz'ü ile aşağıdaki gibi bildirilebilir.

interface IArayuz
{
 int BirSonraki();
 void Sıfırla();

 int Deger
 {
  get;
  set;
 }

 int this [this indeks]
 {
 get;
 }
}

class Sayılar : IArayuz
{
 puplic int BirSonraki()
 {
   //metot gövdesi
 }

puplic void Sıfırla()
{
  //metot gövdesi
}

puplic int Deger
{
get
{
  //get bloğu
}

set
{
 //set bloğu
}
}

puplic int this[this indeks]
{
get
{
  //get bloğu
}

set
{
 //set bloğu
}
}
}

 Sınıflar arasında çok türetme olmamasına rağmen sınıflar birden fazla arayüzüde uygulayabilir. Uygulanacak
arayüzler virgül ile belirtilir. Örneğin IDisposable ve System.Collecitons isim alanında bulunan IEnumarable
yüzünü uygulayan sayılar sınıfı aşağıdaki gibi bildirilebilir.

using System;
using System.collections;

class Deneme : IDisposable, IEnumerable
{
  //Sınıf elemanları
}

Bir arayüzdeki elemanlar içsel olarak puplic olduğu için arayüzü uygulayan sınıfın arayüzdeki elemanları puplic
olarak bildirilmemelidir.

Bir arayüzü uygulayan sınıfın, sadece arayüzdeki elemanlara sahip olabileceği anlamına gelmez. Aynen türetmede
olduğu gibi arayüzdeki elemanların dışında istenildiği kadar yeni eleman eklenebilir.

Sınıflar birbirlerinden nasıl türetilebiliyorsa Arayüzler de birbirlerinden türetilebilir. Temel arayüzdeki bütün
elemanlar türeyen arayüze aktarılır. Böylece istediğimiz kadar eski arayüzü kullanarak daha geniş arayüzleri
oluşturabiliriz. Aşağıda iki arayüzün türetilmesine ilişkin bir örnek verilmiştir.

interface TemelArayuz
{
 void Metot1();
}

interface TureyenArayuz : TemelArayuz
{
  void Metot2();
}

Arayüzden yeni bir Arayüz türetildiğinde dikkat edilmesi gereken hususlar:

Bu kullanım ile TemelArayuz'ü uygulayan bir sınıf sadece Metot1'i uygulamalı iken TureyenArayuz'ü uygulayan bir
sınıf hem Metot1() hem de Metot2()'yi uygulamalıdır. Aksi halde derleme hatası alınır. Sınıflardan farklı olarak
arayüzleri birden fazla arayüz ile türetebiliriz. Örneğin aşağıdaki Arayuz3 bildirimi tamamen geçerlidir.

interface Arayuz1
{
  void Metot1();
}

interface Arayuz2
{
  void Metot2();
}

interface Arayuz3: Arayuz1, Arayuz1
{  void Metot3();
}

Arayüzleri türetirken new anahtar sözcüğü kullanılarak temel arayüzdeki bir eleman gizlenebilir. Bu şekilde
türeyen arayüzde temel arayüzdeki bir elemanla aynı isimli eleman bildirilebilir.

interface Arayuz1
{
  void Metot1();
}
interface Arayuz2 : Arayuz1
{
 new void metot1();
}

Peki bu durumda sadece Arayuz2'yi uyguluyan bir sınıfta Metot1() metodu uygululandığında geçerli bir bildirim olur mu?
 Hayır, çünkü Arayüz1'deki Metot1() metodu gizlenmiş olsa da kalıtım yolu ile Arayuz2'ye aktarılmıştır. Bu yüzden Arayuz2'yi uygulayan bir sınıf hem Arayuz1.Metot1() hem de Arayuz2.metot1() metodunu uygulamak zorundandır. Bunun için Arayuz_adı.Metot_adı ile hangi arayüzdeki metodu uyguladığımızı bildirmeliyiz. Örneğin;

class Deneme: Arayuz2
{
  void Arayuz1.Metot1();
  {
  }

  void Arayuz2.Metot1();
  {
  }
}

Deneme sınıfından bir nesne üzerinden Metot1() metoduna erişmemiz mümkün değildir, çünkü

deneme d= new deneme();
d.Metot1();

deyimiyle hangi arayüze ilişkin metodun çağrıldığı belirsizdir. Bu yüzden yukarıdaki gibi bir kullanım hatalıdır.

O halde Arayuz1.Metot1() ve Arayuz2.Metot1() metotları sadece Deneme sınıfında aşağıdaki gibi tam yolu
belirtilerek kullanılabilir.

void Arayuz2.Metot1()
{
   Arayuz1.Metot1();
}



Sunday, December 9, 2012

Arayüzler (Interface) (c#)


Özet metotlar ile bir özet metodun bulunduğu sınıftan türeyen bir sınıfın mutlaka bu özet metodu devre dışı bırakıp kendine göre uygulaması gerekirdi. Burada amaç aslında bir sınıfın neye benzediğini tespit etmekti. Özet metotlar sayesinde biliyoruz ki bir önceki temel sınıftan türeyen tüm sınıflarda özet metot uygulanmıştır. Bu da tek bir arayüzle birçok iş yapabileceğimiz anlamına gelir. Yani özet sınıfının bir kısım elemanları kendisinden türeyecek sınıflara arayüz niteliği taşımaktadır. Ayrı bir veri türü olan Interface ise tamamen diğer sınıflar için arayüz görevini taşır. Arayüzlerin bütün metotları ve özelliklerinin özet olarak bildirilmiş sınıflardan çok fazla farkı yoktur. Dolayısıyla arayüzlerdeki metotların ve özelliklerin gövdesi yazılamaz. Kısaca arayüzler, kendisini uygulayan sınıfların kesin olarak içerceği özellikleri ve metotları belirler.

 Arayüzler kişisel uygulamalarda pek fazla kullanılmaz ancak özellikle birkaç firmanın ya da programcının üzerinde çalıştığı projelerde ortak bir zemin oluşturabilmek için arayüzlerden faydalanılır.

Arayüz bildirimi:

Arayüzler, interface anahtar sözcüğü kullanılarak bildirilir. Bir arayüzde özellik, indeksleyici, metot, temsilci ve olay bildirimi yapılabilir. Arayüz isimleri geleneksel olarak I harfi ile başlar.

Arayüz bildirimi ile ilgili çeşitli kısıtlamalar vardır.

*Arayüzdeki elemanları statik olarak bildiremeyiz.
*Arayüzdeki eleman bildirimleri içsel olarak puplic oldukları için ayrıca bir elemanı erişim belirleyici ile bildirmek yanlıştır.
*Arayüzler herhangi bir üye değişken içeremez.
*Arayüzlerde yapıcı ve yıkıcı metotlar tanımlanamaz ya da bildirilemez.

Aşağıda iki metot, bir özellik ve bir indeksleyici bildirimi içeren arayüz tasarlayalım.

interface IArayuz
{
  int BirSonraki();
  void Sıfırla();
 
  int Deger
  {
   get;
   set;
  }
 
  int this[int indeks]
  {
  get;
  }
}

Bu arayüzü uygulayan bir sınıfta Arayüzde bulunan bütün elemanların uygulanması gerekir. Deger özelliğinin hem get hem de set blokları olmasına karşın indeksleyicinin sadece get bloğu vardır. Buna rağmen bu arayüzü uygulayacak sınıfta bildirilen indeksleyicinin hem get hem de set bloğu ya da sadece get bloğu olabilir, fakat sadece set bloğu olamaz.

Arayüzlerdeki hatalı kullanımları inceleyelim.

*Asağıdaki Arayüz bildiriminde metot puplic erişim belirleyicisi ile bildirildiği için geçersizdir.

  interface IArayuz
  {
    puplic void Metot();
  }


*Aşağıdaki Arayüz bildiriminde statik metot bildirimi yapıldığı için geçersizdir.

  interface IArayuz
  {
    static void Metot();
  }

 
*Aşağıdaki arayüz bildiriminde ise üye değişkenin bildirilmesi arayüzü geçersiz kılmıştır.

  interface IArayuz
  {
    int a;

    void Metot();

int Ozellik
{
get;
}
  }
 

Saturday, December 1, 2012

Özet (Abstract) Sınıflar (c#)


 Nesne tabanlı programlamada sınıf hiyerarşisi oluştuturken bazen hiyarerşinin en tepesinde bulunan sınıf türünden nesnelerin progmcılar için pek anlamı olmayabilir. Hiyerarşinin en tepesinde bulunan sınıfın kendisinden türetilecek olan alt sınıflar için ortak bir arayüz görevi görmesini isteyebiliriz. Örneğin Memeli sınıfında bulunan Konus() isimli metot çağrıldığında yapacağı iş belli değildir. Yani hangi türdenmemeli türünde konuşacağı belli değildir. Eğer Konus() Metodunu temel sınıfımızda tanımladan direkt kuş, kedi gibi alt sınıflarda tanımlarsak bu sefer Memeli sınıfından türeyecek sınıfların çok biçimliliği desteklememesi söz konusu olacaktır. Bunun için çözüm olarak, Memeli sınıfında Konus() metodu bildirilsin ancak herhangi bir işlevi özelliştirmesin, Memeli sınıfından türeyecek diğer sınıflar için bir arayüz görevi görsün. İşte bu amaçla oluşturulan metotlara ve sınıflara özet metot yada özet sınıf deriz.

   Özet sınıflar ya da özet metotlar abstract anahtar sözcüğü kullanılarak tanımlanır. Temel sınıf içerisinde bildirilen özet(abstract) metotların temel sınıf içerisinde gövdesi yoktur, sadece tanımlaması yapılır. Ancak bu temel sınıftan türeyen bütün sınıflar bu metodu override anahtar sözcüğü ile devre dışı bırakılmalıdır. Özet metotlar zaten sanal olarak görev yaptıkları için virtual anahtar sözcüğü ile sanal olarak tanımlamamıza gerek yoktur.

 Özet metotların Tanımlanması


 Özet sınıflar metot bildiriminin başına abstract anahtar sözcüğünün konulması ile bildirilir.

 abstract puplic void OzetMetot();
 /*Görüldüğü üzere metodumuzun tanımlanması " ; " ile sonlandırılmıştır. Yani metodumuzun gövdesi yoktur.*/

 abstract puplic void OzetMetot(){
 }

 şeklinde gövdesini boş bıraksakta bir metot tanımlamamız yasaklanmıştır.

 Özet sınıfların tanımlanması

  Özet sınıflarda abstract anahtar sözcüğü kullanılarak bildirilirler.  Bir özet sınıf türünden nesneler
 tanımlanamaz. Özet sınıflar ancak kendilerinden türeyen alt sınıflar için arayüz görevi görür.

 abstract class OzetSinif
 {
 }

 Özet sınıflar temel sınıfın tek başına anlamlı bir nesneyi ifade etmediği durumlarda kullanılır.
 Özet sınıfları kullanabilmemiz için özet sınıf türünden yeni sınıflar oluşturmalıyız.


 Her ne kadar Özet sınıftan nesler üretemesekte, özet sınıftan türeyen sınıf nesneleri üzerinden özet sınıfa
 ait yapıcılar kullanılarak özet sınıfın değişkenleri değiştirilebilir. Aşağıda Memeli sınıfından türeyen Kedi
 sınıfından nasıl nesnelerin oluşturulduğunu ve kullanıldığını göreceğiz.

 Using System;

 abstract class Memeli /*Özet sınıf tanımlandı. */
 {
     Puplic double en;
Puplic double boy;

puplic Memeli(double en, double boy)
{
this.en=en;
this.boy=boy;
}
 }

 class Kedi : Memeli
 {
    String Turu;
    puplic Kedi(string turu, double en, double boy) :  base(en,boy)
    {
      this.Turu=turu;
    }
 }

 class MainMetodu
 {
    static void Main()
{
 Kedi kedi = new Kedi("van", 5, 15);
 console.writeline("kedinin eni: "+ kedi.en);
 console.writeline("keninin boyu: " + kedi.boy);


Temel sınıfta oluşturulan abstract metotlar türeyen sınıflarda devre dışı bırakılmalır. Eğer abstract metot
devre dışı bırakılmaz ise derleyici hata verecektir.
Örneğin;

 Using System;

 abstract class Memeli /*Özet sınıf tanımlandı. */
 {
     Puplic double en;
Puplic double boy;

puplic Memeli(double en, double boy)
{
this.en=en;
this.boy=boy;
}

abstract puplic void konus(); /* özet metodumuzu tanımladık. Özet metodumuz Memeli sınıfından türetilecek olan alt sınıflar tarafından devre dışı bırakılmalıdır.*/
 }

 class Kedi : Memeli
 {
    String Turu;
    puplic Kedi(string turu, double en, double boy) :  base(en,boy)
    {
      this.Turu=turu;
    }
 }
 Bu programda derleyici " Kedi türediği sınıfın özet metodu olan Memeli.Konus() metodunu devre dışı
 bırakmamıştır" hatası verecektir. Hatayı düzetlmek için Özet sınıftan türetilen Kedi sınıfı içerisinde
 Özet metot olan Konus Metodunu  Override void Konus()  Tanımlamasıyla devre dışı bırakılmalıdır.


 Metotlar ve sınıflar gibi özellikler de özet olarak bildirilebilir. get ve set bloğu olan bir özet özellik
 aşağıdaki gibi tanımlanır.

 abstract class OzetOzellik
 {
 abstract puplic int A
 {
   get;
   set;
 }
 }

 Ozet ozellik sınıfından türeyen bir sınıf A özelliğini hem get hem de set blokları ile birlikte uygulamak
 zorundadır. Eğer temel sınıfta get yada set bloklarından herhangi biri bildirilmiş olsaydı türeyen sınıfta
 sadece ilgili blok yazdırılırdı.

 abstact class Temel
 {
   abstract puplic int A
   {
    get;
set;
}
  }

 class Tureyen : Temel
 {
 int a;

  puplic override int A
  {
  get{
   return a;
   }
 }

 Özet sınıflar ve metotlar ile genel özellikler

 1.Özet sınıflar türünden nesneler tanımlanamaz.

 2.Özet sınıflar, özet metotlar içerebilirler. Özet metotlar ancak özet sınıfların içinde bildirilebilir.

 3.Özet sınıflar ealed anahtar sözcüğü ile işaretlenemezler.

 4.Özet bir sınıftan türeyen sınıflar temel sınıftaki bütün özet metotları uygulamalıdır. Yani metodun gerçek
 gövdesi türeyen sınıflarda yazılmalıdır.

 5.Bir özet metot ancak bir özet içinde bildirilebilir.

 6.Bütün özet sınıflar içsel olarak sanaldır. bu yüzden virtual olduklarını belirtmeye gerek yoktur.

 7.Özet metotlar türeyen sınıfta mutlaka bildirilmelidir.

 8.Statik metotlar özet olarak bildirilemez.

 9.Sınıflarda özet özellikler de bildirilebilir, türeyen sınıflarda bu özet özellikler override anahtar
 sözcüğü ile tekrar bildirilmelidir.

 10.Bir özet sınıf içinde özet olmayan metotlar da bildirilebilinir. Ancak bir sınıf içinde özet metot bildirilmiş
 ise o sınıf özet olarak tanımlanmalıdır.