C# 3.0 - Extension Methods (Genişletme Metotları)

Serhat tarafından yazılmıştır. 18. Mayıs 2009 13:11

Merhabalar herkese;
Bu makalemizde kısaca C# 3.0 ile gelen LINQ,Anoymous Type,Lambda Expression,Partial Metotlar gibi birçok yenilikten biri olan Extension Methods yani Genişletme metotları hakkında birşeyler yapacağız.Extension metotlar ile Common Language Runtime (CLR) üzerindeki tiplere (int,string vs) veya kendi yazmış olduğumuz tiplere yeni metotlar eklememizi sağlamaktadır.En basitinden bir örnek vermek gerekirse string tipinin içinde bir metot olsa idi ve parametre olarak almış olduğu değeri int tipine return etse idi ne kadar güzel olurdu değil mi ? :).
Genişletme metotları sayesinde LINQ  mimarisi ile gelen birçok metotlardan bazıları olan Reverse,Select,Sum,Take gibi metotlar sayesinde koleksiyonlarımızı,dizilerimizi yani kısacası IEnumerable<T>'yi uygulayan heryerden kullanabiliyoruz.Şöyle incelemek gerekirse,

[code:c#]
    class Ogrenci
    {
        public string OgrenciAdSoyad { get; set; }
        public int Numumara { get; set; }

        public Ogrenci(string adSoyad, int numara)
        {
            OgrenciAdSoyad = adSoyad;
            Numumara = numara;
        }

        public override string ToString()
        {
            return OgrenciAdSoyad + "-" + Numumara;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            List<Ogrenci> ogrenciler = new List<Ogrenci>();
            ogrenciler.Add(new Ogrenci("Serhat Taş", 114));
            ogrenciler.Add(new Ogrenci("Yiğit Taş", 323));

      }
    }
[/code]

Yukarıda Ogrenci  diye bir tip tanımlanıp daha sonra tanımlanmış olan Ogrenci tipinden bir generic List<T> tanımlanıyor.Ve tanımlamış olduğumuz generic koleksiyon üzerindeki üyelere baktığımızda ise birçok extension metodun gelmiş olduğunu görüyorum.

Peki nereden geldi bu kadar metot ? Baktığımızda bir koleksiyonda olmaması gereken metotlarmış gibi gözüküyor olabilir.Burada gözüken metotlar aslında IEnumerable<T> üzerinden gelen metotlardır.Yani açıkcası birer Extension(genişletme) metotlardır.Böylece buradan gelen metotların artık ogrenciler nesnesi üzerinden gelmediğini anlayabiliriz.Tüm bunlar System.Linq.Enumerable isimli static bir classın üyeleri olmaktadır.Bu sebepten dolayı Enumerable  sınıfının programımızda erişebildiği heryerde bu genişletme metotlarını kullanarak işlemler yapabiliriz.
Array classı'da Enumerable classına erişebildiğinden basit bir dizi tanımladığımızda bile dizimizin üyesi olmayan genişletme metodu olarak adlandırılan static Enumerable classı içerisinde tanımlanmış birçok metodu kullanabilir duruma gelebiliriz.Üyelere baktığımızda genişletme metotları olduğunu anlayabiliyoruz.Zaten metot simgeleri farklı olduğu gibi açıklama olarak da bunun bir extension üye olduğunu söylüyor bizlere.

Ve aslında da LINQ dediğimiz mimarinin bu System.Linq.Enumerable static classının içerisinde tanımlanmış olan metotları kullanıyor olduğunu söyleyebiliriz :) .Eğer kendi Extension metotlarımızı yazacak isek uygulamamız gereken önemli kurallar bulunmaktadır.

1-Genişletme metotlarımız mutlaka static bir Class içerisinde olmalıdır
2-Classların içerisindeki metotlarımız static olarak tanımlanmalıdır
3-Ve son olarakda yazdığımız static metotların ilk parametresi o metodun hangi tip üzerinden çağırıldığında gelmesini istiyor isek onu this anahtar kelimesi ile belirtmeliyiz.

Basit olarak mantığını anlamak için bir örnek yapalım.Mesela bir metodumuz olsun string bir tip üzerinden çağırıldığında çağırıldığı değerin tüm harflerini büyük yapsın.ToUpper() bu işi görüyor fakat biz kendimiz yaparak yine bu metodu kullanalım ama yazdığımız metot kendi extension metodumuz olsun.Bakalım nasıl oluyormuş :)

[code:c#]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GenisletmeMetotlari
{
    class Program
    {
        static void Main(string[] args)
        {
            string isim = "serhat";
            Console.WriteLine(isim.MetiniBuyut());
        }
    }

    //Extension metodumun bulunduğu static classım.
    static class ExtensionMetotlar
    {
        //string bir tip üzerinden artık bu metodumuz çağırılarak hangi değer üzerinde ise onu büyük harfe çevirecektir
        public static string MetiniBuyut(this string s)
        {
            return s.ToUpper();
        }
    }
}
[/code]

Yukarıdaki örneğe bakacak olursak kurallarda denildiği gibi eğer bir static metot yazılacak ise öncelikli olarak static bir class tanımlanmalıdır.Ve  biz ExtensionMetotlar adında tanımladık.Daha sonra amacımız string bir tip üzerinden  kendi yazdığımız bir metodu çalıştırmak için ise yine static olarak tanımladık fakat bu sefer ilk parametresini this anahtar kelimesi ile harici olarak çalıştırmak istediğimiz tipin adını yazdık.Biz bu metodumuzda metinsel bir işlem yapacağımızdan this string dediğimizde artık bu metodumuzu kullanabiliyor olacağız.Extension metotlara giriş yaptığımızda nasıl Enumerable classı içerisinde tanımlanmış olan genişletme metotlarına ulaşıyor isek bizimde programımızın içerisinde ulaştığımızı görüyoruz.Intelisense bize destek vermektedir bu konuda ve listelenen bir metodun hangisinin gerçek tipin hangisi daha sonradan bu tipe genişletilerek eklendiğini belli etmektedir.


Çalıştırdığımızda da istediğimiz sonucu elde etmiş oluyoruz.Bakın string tipine böylece en basitinden bir metot ekledik :)

Ve diğer önemli bir konu.Bizler kendi yazmış olduğumuz Extension metotlara Overloading  yani aşırı yüklenmiş  hale getirebiliyoruz.Extension metotların bulunduğu classın görünümü aşağıdaki gibidir.

[code:c#]  
    //Extension metodumun bulunduğu static classım.
    static class ExtensionMetotlar
    {
        //string bir tip üzerinden artık bu metodumuz çağırılarak hangi değer üzerinde ise onu büyük harfe çevirecektir
        public static string MetiniBuyut(this string s)
        {
            return s.ToUpper();
        }

        //tek parametreli int extension metot
        public static int SayiIslem(this int s)
        {
            return s * 2;
        }

        //iki parametreli int extension metot
        public static int SayiIslem(this int s, int s1)
        {
            return s * s1;
        }
    }
[/code]
 

Metotları aşırı yükledikten sonra Main'e gittiğimizde aşırı yüklenme işinin başarılı bir şekilde çalıştığını görüyoruz.Tanımlarken parametre sayıları ve tipleri önemlidir.Bunlarada bildiğimiz gibi metot imzası (Method Signature) denilmektedir.

 

Ve diğer güzel bir özelliktende bahsedelim kısaca :) .Farzedelimki 10 tane tipiniz var (class ) hepsi bir interface'i arayüz uygulamış.Ve siz tüm bu 10 class'dan oluşacak nesnelerede ayı ayrı birer metot yazmak yerine tek bir metotla işleminizi yapmak istiyorsunuz.Nasıl olabilir ? .Tüm bu 10 sınıfında uygulamış olduğu interface'e genişletme metodu eklesek nasıl olurdu ki acaba ? . Bence çok güzel olurdu :) .Aşağıdaki gibi iki tane class ve bir tanede bu class'ların uygulamış olduğu interface'in olduğunu varsayıyoruz.

[code:c#]  
    interface OrnekArayuz
    {
         void InterfaceMetot();
    }

    class Sinif1 : OrnekArayuz
    {
        public void InterfaceMetot()
        {
            Console.WriteLine("Sinif1 isimli metot");
        }
    }
    class Sinif2 : OrnekArayuz
    {
        public void InterfaceMetot()
        {
            Console.WriteLine("Sınıf2 isimli metot");
        }
    }
[/code]
  

Ve şimdi Main metodumuza gidelim bakalım nesnelerimiz ne alemde.

Görüldüğü gibi iki class'ın ortak uyguladığı bir arayüzdeki metodu kullanarak nesnemiz üzerinden interface'deki metot yapısına erişebiliyoruz.Çalıştırdığımızda aşağıdaki görüntü oluşacaktır tahmin ettiğiniz gibi.

Bu sonuç zaten beklenen birşeydi.Peki örneğimizi kurkularken bu class'ların 1-2 tane değilde 10 tane olduğunu ve bu tüm class'larımıza Extension özelliğini kullanarak yeni bir metot eklemekti amacımız.Eğer bir Extension Metodu Interface'e uygular iseniz o interface'den türeyen tüm tiplerimizden extension metoda erişebiliriz arkadaşlar.Biz burada kendi yazmış olduğumuz bir arayüze extension metot ekleyeceğiz.NET Framework'in içerisinde tanımlanmış olan interface'lere de genişletme metotlarını ekliyerek oldukça kolay kodlanabilen uygulamalar yazabiliriz.Bu işlemi yapabilmek için yukarıdaki Extension metot tanımlama kurallarını hatırlayalım.Metodumuz static olmalı,ilk parametresi uygulayacağımız tipin adını vermeliyiz ve bu metot bir static class içersinde olmalı idi.Peki yukarıdaki class'ların yanına aşağıdaki class'ımızda ekleyelim.

[code:c#] 
    static class InterfaceExtensionEkle
    {
        public static void ExtensionMetot(this OrnekArayuz o)
        {
            Console.WriteLine("OrnekArayüz isimli interface'e eklenen extension metot");
        }
    }
[/code]
   

Burada Extension metodumuzun ilk parametresine bakacak olursak demiştik ki bu metodu eklemek istediğimiz tipin adını yazarız.Bizde buraya bir interface tip adını verdiğimizden dolayı artık programımızın içerisinde bu interface'i uygulamış tüm class'lardan  ExtensionMetot isimli tanımlamış olduğumuz metoda erişebileceğiz.Ekledikten sonraki tekrar Main metoduna gidelim bakalım neler olmuş.

Görüldüğü gibi artık istediğimiz olmuştur.Tüm class'lara gidip istediğimiz metodu yazmak yerine bu class'ların uyguladığı bir interface'e extension metot eklediğimizden dolayı bu arayüzü uygulamış tüm nesnelerimiz üzerinden erişebiliyoruz.Intelisense yukarıda dediğimiz gibi bunun bir genişletme metodu olduğunu belli ediyor zaten. Aşağıdaki gibi iki nesnemiz üzerinden Extension metodları çağırır isek aşağıdaki görünümü elde edebiliriz.



Kendi class'larımıza ,interface'lerimize ve framework'deki tipe extension metot işlemini gerçekleştirdik.Ve dedik ki .NET Framework içindeki inteface'lerede uygulanabildiğini söyledik.Peki birde ona bakalım  , aslında diğerlerinden hiç bir farkı yok :). Amacımız mantığını anlamak olduğundan IEnumerable arayüzü bu örnek için çok güzel.Örneğimizin kurgusu şöyle olsun.Bir extension metot yazalım ve IEnumerable<int> tipinden türeyen tüm generic koleksiyonlar(Stack,List vb.) kullanabilsin.Ve extension metotda olması gereken kurallara göre aşağıda oluşturuyorum.

[code:c#]  
    static class InterfaceExtensionEkle
    {
        public static IEnumerable<int> HariciMetot2(this IEnumerable<int> gelen)
        {
            List<int> liste = new List<int>();

            foreach (int i in gelen)
            {
                if (i % 2 == 0)
                    liste.Add(i);
            }
            return liste;
        }
    }
[/code]
   

Burada geri dönüş tipi IEnumerable<int> olan adı HariciMetot2 ve ilk parametresindede bunun bir extension metot olacağından hangi tip üzerinden erişmek istiyor isem onu belirtiyorum.Ben burada IEnumerable<int> dediğimden .NET Framework'deki  IEnumerable<int> tipindeki tüm tiplerimden bu metoduma ulaşabileceğim.Ve metodun amacıda içerisinde oluşturğum int tipinden olan Generic List'ime  hangi IEnumerable<int>'i uygulamış tip üzerinden çağırılır ise çağırıldığı koleksiyonun içindeki üyelere bakarak çift olan sayıları bulup daha sonra bunu geri döndürüyorum.Böyle basit bir metot.Peki şimdi programımızda kullanalım bakalım nasıl çalışıyor.


Görüldüğü gibi int tipinden generic bir List koleksiyonu oluşturmuşum ve içerisinde 1'den 10'a kadar değerler vermişim.Daha sonra benim amacım çift sayıları bulmak olduğundan IEnumerable<int> tipinden bir nesneme IEnumerable<int>'i uygulamış bir koleksiyon nesnesi üzerinden çift sayıları bulan bir extensin metoda erişmeye çalışıyorum.Ve HariciMetot2 adında bir metotun gözüktüğünü görüyorum.Genişletme metodumun uygulanacağı tip IEnumerable<int> olduğundan generic List'imde bu tipten yani IEnumerable<int>'den etkilendiğinden sayilar adındaki diğer tüm extension'lara erişebildiğim gibi kendi yazmış olduğum genişletme metoduna erişmiş durumdayım.Bu metot sayilar nesnesindeki sayıların içerisindeki çift sayıları bularak ÇiftSayilar adındaki nesneme aktaracaktır.Daha sonra main'e giderek yazmış olduğum metodu kullanıp çift sayıları ekrana başarılı birşekilde yazdırabiliyorum.

[code:c#]   

            List<int> sayilar = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
            IEnumerable<int> ciftSayilar = sayilar.HariciMetot2();
            foreach(int i in ciftSayilar)
                Console.WriteLine(i);
[/code]
   
Ve sonuca baktığımda istediğimizin olduğunu görebiliyoruz.


Bu şekilde interface'lerede genişletme metotları yazarak birçok işi daha kolay hale getirebiliyoruz :)

Anlattıklarımı kısaca toparlar isek biz Class'lara ve Interface'lere Extension metot ekledik.Fakat Struct(Yapı)'lara da genişletme metotları yazabiliriz.Genişletme metotlarımızın aşırı yüklenmiş hallerini yazabir. Genişletme metotları hangi tipe uygulanacak ise ilk parametresinde this anahtar kelimesi ile bildirilmedilir .Ve son olarak da genişletme metotları static bir class içerisinde static anahtar kelimesi ile kendiside işaretlenmelidir diye özetleyebiliriz.

Bu yazımda kısaca C# 3.0 ile gelen Extension Metotlara deyinmek istemiştim.Faydalı olması dileğiyle iyi çalışmalar herkese :)

Serhat TAŞ

serhat@serhattas.net

5 kişi tarafından 4.4 olarak değerlendirildi

  • Currently 4,4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Etiketler: ,

C# & .NET

Yorumlar

Yorum ekle


(Gravatar simgesini gösterecek)  

biuquote
  • Yorum
  • Canlı önizleme
Loading



Powered by BlogEngine.NET 1.4.5.0
Bu tema Mads Kristensen tarafından yapılmıştır ve Türkçeleştirilmesi Blog Engine Türkiye ekibi tarafından yapılmıştır.

Son Yorumlar

Comment RSS

Yasal Uyarı

Bu sitede sunulan tüm bilgi ve dökümanların kullanımından ve sitede yapılan kullanıcı yorumlarından (siyasi içerik,hakaret vb.) doğacak sorunlardan yazar sorumlu tutulamaz. 

İçeriğin kaynak belirtilmeden kopyalanması yasaktır !

SERHAT TAŞ

© Copyright 2010