Action, Func ve Predicate Delegeleri

Delegeler metodları işaret eden ve işaret ettikleri metodlarla aynı imzaya sahip olan yani aynı tipte parametrelere ve dönüş değerlerine sahip olan yapılardır.  Delegeleri event tabanlı programlamada, asenkron programlamada, thread programlamada vb bir çok yerde kullanırız. Makalenin asıl amacı genel olarak delege yapısı olmadığı için detaylarına girmeyeceğim.

Pekala yazımızın konusu olan Action, Func ve Predicate neyi temsil eder? Başlıktan da anlaşılacağı üzere bunlar da .Net framework içerisinde bulunan, bizler için önceden hazırlanmış olan delegelerdir. Çok fazla kelimelerle uğraşmadan kod üzerinde görelim.

Action delegesinin imzasına baktığınızda aşağıdaki gibi bir kod göreceksiniz.

public delegate void Action<in T>(T obj);

Burada Action delegemizin T tipinde yani herhangi bir tipte parametre alan sonrasında da void dönüş yapan metodları işaret edebildiğini görüyoruz.

Örneğin normal delegeler ile aşağıdaki şekilde yazdığımız bir kodu

        delegate void NormalDelege(long sayi);

        private void button1_Click(object sender, EventArgs e)
        {
            NormalDelege karesiniAlDelegem;
            karesiniAlDelegem = karesiniAl;
            karesiniAlDelegem(3);
        }

        private void karesiniAl(long sayi)
        {
            MessageBox.Show(Math.Pow(sayi,2).ToString());
        }

Action delegesi ile aşağıdaki gibi yazabiliriz.

        private void button1_Click(object sender, EventArgs e)
        {
            Action<long> actionIleKaresiniAl;
            actionIleKaresiniAl = karesiniAl;
            actionIleKaresiniAl(3);
        }

        private void karesiniAl(long sayi)
        {
            MessageBox.Show(Math.Pow(sayi,2).ToString());
        }

Action delegesi olduğunun farkına varmasak da kodlarımız içinde lambda ile birlikte bu delegeyi oldukça fazla kullanmaktayız. Örneğin aşağıdaki kodda (kodun anlamsız olduğunun farkındayım amaç net şekilde gösterebilmek 🙂 )

sayilar.ForEach(x => MessageBox.Show(Math.Pow(x, 2).ToString()));

ForEach methodunun tanımına gittiğimizde Action tipinde bir parametre aldığını görebiliriz.

public void ForEach(Action<T> action);

Yani aslında biz ForEach içerisine long tipinde bir değer alan ve içerisinde bu değerin karesini alıp MessageBox ile gösteren bir fonksyion yazdık.

Func delegesi Action’a benzer bir yapıdadır ama Actiondan farklı olarak bir dönüş değeri vardır. Func delegesinin tanımlarına baktığımızda iki farklı kullanım görebiliriz. Hiç parametre almadan bir değer dönebilir.

public delegate TResult Func<out TResult>()

Ya da bir parametre alıp bir değer dönebilir.

public delegate TResult Func<in T, out TResult>(
	T arg
)

Aşağıdaki kod örneğinde butonun click eventinde öncelikle Func delegesi parametre almayıp string dönen bir metodu işaret ederken, sonrasında delegemiz string bir değişken alıp, string bir değişken dönen bir metodu işaret etmektedir.

        private void button1_Click(object sender, EventArgs e)
        {
            Func<string> stringDonenFunc;
            stringDonenFunc = merhabaDe;
            MessageBox.Show(stringDonenFunc());

            Func<long, string> longAlipStringDonenFunc;
            longAlipStringDonenFunc = karesiniAl;
            MessageBox.Show(longAlipStringDonenFunc(3));
        }

        private string merhabaDe()
        {
            return "Merhaba";
        }

        private string karesiniAl(long sayi)
        {
            return Math.Pow(sayi, 2).ToString();
        }

Func delegesini de farkında olmasak da linq sorgularımızda kullanmaktayız.  Listeler üzerinde çalıştırdığımız Select , Where vb komutlarında tanımlarına baktığımızda Func tipinde parametre aldıklarını görürüz.

Predicate delegesi ise tam olarak Func<T, bool> parametresinin yaptığı işi yapar. Yani herhangi bir tipteki değişkeni alır ve geriye boolean bir değer döner.  Kullanımı da benzer şekildedir.

        private void button1_Click(object sender, EventArgs e)
        {
            Predicate<long> predicateDelegesi;
            predicateDelegesi = ikiHaneliMi;
            if(predicateDelegesi(55))
                MessageBox.Show("Evet");
            else
                MessageBox.Show("Hayır");
        }
        private bool ikiHaneliMi(long sayi)
        {
            return sayi < 100 && sayi > 9;
        }

Kısa bir şekilde Action, Func ve Predicate delegelerini ve kullanımlarını anlatmaya çalıştım. Eğer herhangi bir sorunuz, eleştiriniz, öneriniz varsa yorum yazarsanız sevinirim.

Çevik Kalın 🙂

 

String Birleştirme Ve Performans

Uygulamalırımızda en çok kullandığımız değişken tiplerinden bir tanesi de string’dir. Bir çok işlemimizi string’ler üzerinde yaparız. Ancak strinf değişkenleri kullanırken dikkat etmemiz gereken ve bize performans açısından büyük katkı sağlayacak bir kaç nokta vardır.

Hepimiz uygulamalarımızda

 string x = “”;
        for (int i=0; i <= 100000; i++)
        {
            x += i.toString();
        }

tarzında bir string birleştirme işlemi gerçekleştirmişizdir. Bu tarz bir string birleştirme işlemi küçük döngülerde bir problem oluşturmazken büyük döngülerde başımıza ciddi performans problemleri çıkarabilir. Bunun nedeni ise böyle bir birleştirme işleminde bütün atama işlemlerinde yeni bir nesne oluşturulmasıdır. Yani döngümüzün ilk tekrarında x değerini alır, yeni bir string değişken oluşturur. Eski değeri yeni değişkene atar ve sonrasında verdiğimiz string değeri buna ekler. Bir sonraki adımda yine yeni bir nesne oluşturulur, bu kez ikinci nesnedeki değer üçüncüye atılır ve adımlar bu şekilde devam eder. Yani yukarıdaki gibi bir döngü yazmış iseniz, sadece string birleştirme işlemi için 100000 ekstra nesne oluşturulur. Buna uygulamanıza esktra yük demektir.

Bu soruna çözüm ise StringBuilder. Yukarıdaki kodu aşağıdaki şekilde de yazabiliriz.

        StringBuilder builder = new StringBuilder();
        for (int i=0; i < 100000; i++)
        {
            builder.Append(i.toString());
        }
       string x = builder.ToString();

Kodumuzu bu hale getirdiğimizde bu kod parçası için yaklaşık 10 kat hız artışı sağlamaktadır.

Peki heryerde string oluşturma işlemlerimizi bu şekilde mi yapmalıyız. Tabii ki hayır. Örneğin

string tamad=ad+” “+soyad;

kod parçası yerine

 StringBuilder builder = new StringBuilder();
 builder.Append (ad);
 builder.Append (” “);
 builder.Append (soyad);
 string tamad= builder.ToString();

kod parçasını kullanmak bize bir performans artışı sağlamayacağı gibi okunurluğu da azaltacaktır.

EQATEC Profiler

          Bir programdan bahsetmek istiyorum bugün. Adı başlıktan da anlaşılacağı gibi EQATEC Profiler. Peki ne işe yarar bu program. Yazdığınız uygulamanın performansını gösterir diyebiliriz özetle. Daha doğrusu programınızda hangi nesneler kaç kez çağrılmış, bunlar ne kadar süre işlem gerçekleştirmiş, en fazla zaman harcanan kısım hangisi gibi bilgilere EQATEC Profiler sayesinde ulaşabiliyorsunuz. En güzel yanı ücretsiz olması, piyasada ücretli ya da ücretsiz daha iyi uygulamalar tabii ki vardır. Ama bu bana fazlasıyla yardımcı oldu.

        Peki ben nasıl tanıştım bu programla. Continue…