Temsilciler ve lambda ifadeleri

Temsilciler belirli bir yöntem imzasını belirten bir tür tanımlar. Bu imzayı yerine alan bir yöntem (statik veya örnek), bu tür bir değişkene atanabilir, ardından doğrudan çağrılabilir (uygun bağımsız değişkenlerle) veya bağımsız değişkenin kendisi olarak başka bir yönteme geçirebilirsiniz ve ardından çağrılır. Aşağıdaki örnekte temsilci kullanımı gösterildi.

using System;
using System.Linq;

public class Program
{
    public delegate string Reverse(string s);

    static string ReverseString(string s)
    {
        return new string(s.Reverse().ToArray());
    }

    static void Main(string[] args)
    {
        Reverse rev = ReverseString;

        Console.WriteLine(rev("a string"));
    }
}
  • Satır, belirli bir imzanın temsilci türünü oluşturur, bu durumda bir dize parametresi alan ve sonra bir public delegate string Reverse(string s); dize parametresi döndüren bir yöntem.
  • Tanımlanan static string ReverseString(string s) temsilci türüyle tam olarak aynı imzaya sahip olan yöntemi, temsilciyi kullanır.
  • Reverse rev = ReverseString;Satırda, ilgili temsilci türünde bir değişkene yöntem ataydığınız gösterir.
  • Satır, Console.WriteLine(rev("a string")); temsilciyi çağırmak için bir temsilci türünde bir değişkenin nasıl kullanıla bir olduğunu gösterir.

Geliştirme sürecini basit hale getirmek için .NET, programcıların yeniden kullanacı olarak yeni türler oluşturmak zorunda değil, temsilci türleri kümesi içerir. Bu türler Func<> , Action<> ve Predicate<> 'dır ve yeni temsilci türleri tanımlamak zorunda kalmadan kullanılabilir. Üç türün kullanım amaçlanan şekilde ilgili olması gereken bazı farklar vardır:

  • Action<> , temsilcinin bağımsız değişkenlerini kullanarak bir eylem gerçekleştirme ihtiyacı olduğunda kullanılır. Kapsüllene yöntemi bir değer dönmez.
  • Func<> genellikle eldeki bir dönüşüm olduğunda kullanılır; diğer bir ifade, temsilcinin bağımsız değişkenlerini farklı bir sonuça dönüştürmenin gerekmesidir. Projeksiyonlar iyi bir örnektir. Kapsüllene yöntemi belirtilen bir değer döndürür.
  • Predicate<> bağımsız değişkeninin temsilcinin koşuluna uygun olup olmadığını belirlemeniz gerekirken kullanılır. Ayrıca, yöntemi bir Func<T, bool> boole değeri döndüren bir olarak da yazıldığı anlamına gelir.

Şimdi yukarıdaki örneğimizi alıp özel tür yerine temsilciyi Func<> kullanarak yeniden yazabilirsiniz. Program tam olarak aynı şekilde çalışmaya devam eder.

using System;
using System.Linq;

public class Program
{
    static string ReverseString(string s)
    {
        return new string(s.Reverse().ToArray());
    }

    static void Main(string[] args)
    {
        Func<string, string> rev = ReverseString;

        Console.WriteLine(rev("a string"));
    }
}

Bu basit örnekte yöntemin dışında tanımlanmış bir Main yöntemin olması biraz gereksiz gibi görünüyor. .NET Framework 2.0'da, herhangi bir ek tür veya yöntem belirtmek zorunda kalmadan "satır içi" temsilciler oluşturmanıza izin verilen anonim temsilciler kavramı tanıtıldı.

Aşağıdaki örnekte anonim temsilci, bir listeyi yalnızca doğru sayılara filtreledi ve konsola yazdırdı.

using System;
using System.Collections.Generic;

public class Program
{
    public static void Main(string[] args)
    {
        List<int> list = new List<int>();

        for (int i = 1; i <= 100; i++)
        {
            list.Add(i);
        }

        List<int> result = list.FindAll(
          delegate (int no)
          {
              return (no % 2 == 0);
          }
        );

        foreach (var item in result)
        {
            Console.WriteLine(item);
        }
    }
}

Gördüğünüz gibi temsilcinin gövdesi, diğer temsilciler gibi yalnızca bir ifade kümesidir. Ancak bunun ayrı bir tanım olması yerine yöntemine yapılan çağrıda bunu geçici olarak List<T>.FindAll tanıttık.

Ancak, bu yaklaşımla bile atacak çok kod vardır. Lambda ifadeleri burada ortaya gelir. Kısaca lambda ifadeleri (kısaca "lambdalar"), C# 3.0'da Language Integrated Query'nin (LINQ) temel yapı taşlarından biri olarak tanıtıldı. Bunlar yalnızca temsilcileri kullanmak için daha kullanışlı bir söz dizimidir. Bir imza ve yöntem gövdesi bildirmektedir, ancak temsilciye atanmadıkça kendi resmi kimlikleri yok. Temsilcilerden farklı olarak, bunlar olay kaydının sağ tarafı olarak veya çeşitli LINQ yan tümceleri ve yöntemlerinde doğrudan atanabilir.

Bir lambda ifadesi, temsilci belirtmenin başka bir yolu olduğu için, anonim temsilci yerine lambda ifadesi kullanmak için yukarıdaki örneği yeniden yaza uygulamamız gerekir.

using System;
using System.Collections.Generic;

public class Program
{
    public static void Main(string[] args)
    {
        List<int> list = new List<int>();

        for (int i = 1; i <= 100; i++)
        {
            list.Add(i);
        }

        List<int> result = list.FindAll(i => i % 2 == 0);

        foreach (var item in result)
        {
            Console.WriteLine(item);
        }
    }
}

Yukarıdaki örnekte kullanılan lambda ifadesi i => i % 2 == 0 şeklindedir. Yine, temsilciler kullanmak için kullanışlı bir söz dizimidir. Altta neler olduğu, anonim temsilciyle olan durumla benzerdir.

Yine, lambdalar yalnızca temsilcilerdir ve bu da aşağıdaki kod parçacığında gösterildiği gibi herhangi bir sorun olmadan olay işleyicisi olarak kullanılaları anlamına gelir.

public MainWindow()
{
    InitializeComponent();

    Loaded += (o, e) =>
    {
        this.Title = "Loaded";
    };
}

Bu += bağlamda işleci, bir olayına abone olmak için kullanılır. Daha fazla bilgi için bkz. Olaylara abone olma ve abonelikten çıkma.

Daha fazla okuma ve kaynak