Aracılığıyla paylaş


Lambda İfadeleri (C# Programlama Kılavuzu)

Bir lambda ifadesi; temsilci veya ifade ağacı türleri oluşturmak için kullanabileceğiniz anonim bir işlevdir.Lambda ifadeleri kullanarak, bağımsız değişken yerine geçebilecek veya işlev çağrılarının değeri olarak döndürülebilecek, yerel işlevler yazabilirsiniz.Lambda ifadeleri LINQ sorgu ifadeleri yazmak için özellikle yararlıdır.

Lambda ifadesi oluşturmak için, => lambda işlecinin sol tarafında giriş parametreleri belirtin ve ifadeyi veya deyim bloğunu diğer tarafa yerleştirin.Örneğin, x => x * x lambda ifadesi, x adlı bir parametre belirtir ve x değerinin karesini döndürür.Bu ifadeyi aşağıdaki örnekte gösterildiği gibi bir temsilci türüne atayabilirsiniz:

delegate int del(int i);
static void Main(string[] args)
{
    del myDelegate = x => x * x;
    int j = myDelegate(5); //j = 25
}

Bir ifade ağacı türü oluşturmak için:

using System.Linq.Expressions;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Expression<del> myET = x => x * x;
        }
    }
}

=> işleci aramayla (=) aynı önceliğe sahiptir ve sağdan birleşir (İşleçler makalesindeki “Birleşme” bölümüne bakın).

Lambda ifadeleri yöntem tabanlı LINQ sorgularında standart sorgu işleci yöntemlerinin bağımsız değişkenleri olarak kullanılır, örneğin Where``1.

Where``1 yöntemini Enumerable sınıfının içinde çağırmak için yöntem tabanlı sözdizimi kullandığınızda (Nesneler için LINQ ve LINQ - XML durumlarında olduğu gibi) parametre, temsilci türüdür Func.Lambda ifadesi, bu temsilciyi oluşturmak için en kullanışlı yoldur.Aynı yöntemi örneğin (LINQ - SQL ürününde yaptığınız gibi) Queryable sınıfında çağırırsanız, parametre türü bir Expression<Func> olur; burada Func, on altı adede kadar giriş parametresi alan Func temsilcilerinden biridir.Yine, Lambda ifadesi bu ifade ağacını oluşturmanın yalnızca çok kısa bir yoludur.Aslında lambdadan oluşturulan nesnenin türü farklı olsa da, lambdalar Where çağrılarının benzer görünmesine izin verir.

Önceki örnekte, temsilci imzasında örtük olarak yazılmış ve int türünde bir giriş parametresi olduğuna ve bir int döndürdüğüne dikkat edin.Lambda ifadesi bu türden bir temsilciye dönüştürülebilir çünkü ayrıca bir giriş parametresi (x) ve derleyicinin dolaylı olarak int türüne çevirebildiği bir dönüş değerine sahiptir. (Tür çıkarımı, ilerleyen bölümlerde daha ayrıntılı bir şekilde tartışılmıştır.) Temsilci, giriş parametresi 5 kullanılarak çağrıldığında 25 sonucunu döndürür.

Lambda ifadelerinin is veya as işlecinin sol tarafında olmasına izin verilmez.

Anonim yöntemler için uygulanan tüm kısıtlamalar lambda ifadeleri için de geçerlidir.Daha fazla bilgi için bkz. Anonim Yöntemler (C# Programlama Kılavuzu).

Lambda İfadeleri

=> işlecinin sağ tarafında bir ifade olan bir lambda ifadesine bir ifadesi lambdası denir.İfade lambdaları İfade Ağaçları (C# ve Visual Basic) oluşturulurken sıkça kullanılır.Bir lambda ifadesi, ifadenin sonucunu verir ve aşağıdaki temel biçimi alır:

(input parameters) => expression

Parantezler yalnızca lambdanın bir çıktı parametresi varsa isteğe bağlıdır; aksi takdirde bunlar gereklidir.İki veya daha fazla giriş parametresi, ayraç içinde virgülle ayrılır:

(x, y) => x == y

Bazen derleyicinin giriş türlerini çıkarması zor veya imkansız olabilir.Bu durumda türleri aşağıdaki örnekte olduğu gibi açıkça belirtebilirsiniz:

(int x, string s) => s.Length > x

Boş ayraçlarla sıfır giriş parametrelerini belirtin:

() => SomeMethod()

Önceki örnekte bir lambda ifadesi gövdesinin yöntem çağrısından oluşabileceğini unutmayın.Ancak, .NET Framework dışında, örneğin SQL Server'da değerlendirilen ifade ağaçları oluşturuyorsanız, lambda ifadelerinde yöntem çağrısı kullanmamanız gerekir.Yöntemler .NET ortak dil çalışma zamanı bağlamının dışında anlamlı olmayacaktır.

Deyim Lambdaları

Ayraçlar arasındaki deyimler hariç statement lambda, expression lambda'ya benzer:

(input parameters) => {statement;}

Bir lambda deyiminin gövdesi herhangi bir sayıda deyimden oluşabilir; ancak, uygulamada genellikle iki veya üçten fazla değildir.

delegate void TestDelegate(string s);
…
TestDelegate myDel = n => { string s = n + " " + "World"; Console.WriteLine(s); };
myDel("Hello");

Anonim yöntemler gibi deyim lambdaları da ifade ağacı oluşturmak için kullanılamaz.

Zaman Uyumsuz Lambdalar

async ve await anahtar sözcüklerini kullanarak zaman uyumsuz işleme içeren lambda ifadeleri ve deyimlerini kolayca oluşturabilirsiniz.Örneğin, aşağıdaki Windows Forms örneği, ExampleMethodAsync zaman uyumsuz yöntemini çağıran ve bekleyen bir olay işleyici içerir.

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private async void button1_Click(object sender, EventArgs e)
    {
        // ExampleMethodAsync returns a Task.
        await ExampleMethodAsync();
        textBox1.Text += "\r\nControl returned to Click event handler.\r\n";
    }

    async Task ExampleMethodAsync()
    {
        // The following line simulates a task-returning asynchronous process.
        await Task.Delay(1000);
    }
}

Zaman uyumsuz lambda kullanarak aynı olay işleyicisini ekleyebilirsiniz.Bu işleyiciyi eklemek için aşağıdaki örnekte göründüğü gibi lambda parametre listesinden önce bir async değiştirici ekleyin.

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        button1.Click += async (sender, e) =>
        {
            // ExampleMethodAsync returns a Task.
            await ExampleMethodAsync();
            textBox1.Text += "\r\nControl returned to Click event handler.\r\n";
        };
    }

    async Task ExampleMethodAsync()
    {
        // The following line simulates a task-returning asynchronous process.
        await Task.Delay(1000);
    }
}

Zaman uyumsuz yöntemlerin nasıl oluşturulacağı ve kullanılacağı hakkında daha fazla bilgi için bkz. Async ve Await ile Zaman Uyumsuz Programlama (C# ve Visual Basic).

Standart Sorgu İşlevleriyle Lambda İfadeleri

Standard sorgu işleçlerinin çoğu, türü Func genel temsilci ailesinden olan bir giriş parametresine sahiptir.Bu temsilciler girdi parametrelerinin sayısını ve türünü ve temsilcinin döndürdüğü değerin türünü tanımlamak için tür parametreleri kullanır.Func temsilcileri, bir kaynak veri kümesindeki her öğeye uygulanan kullanıcı tanımlı ifadelerin kapsüllenmesi için son derece kullanışlıdır.Örneğin, aşağıdaki temsilci türünü göz önünde bulundurun:

public delegate TResult Func<TArg0, TResult>(TArg0 arg0)

Temsilci; int değerinin giriş parametresi, bool değerinin dönüş değeri olduğu yerde Func<int,bool> myFunc olarak oluşturulabilir.Dönüş değeri her zaman son tür parametresinde belirtilir.Func<int, string, bool> bir temsilci ile int ve string olmak üzere iki giriş parametresi ve bool dönüş türü tanımlar.Aşağıdaki Func temsilcisi çağrıldığında, giriş parametresinin 5'e eşit olup olmadığını belirtmek için true ya da false döndürür:

Func<int, bool> myFunc = x => x == 5;
bool result = myFunc(4); // returns false of course

Bağımsız değişken türü Expression<Func> olduğunda, örneğin standart sorgu işleçlerinde tanımlı System.Linq.Queryable gibi, lambda ifadesi sağlayabilirsiniz.Expression<Func> bağımsız değişken belirlediğinizde lambda ifade ağacında derlenecek.

Standart sorgu işleci olan Count``1 yöntemi burada gösterilmektedir:

int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
int oddNumbers = numbers.Count(n => n % 2 == 1);

Derleyici giriş parametresinin türünü çıkarabilir veya bunu açıkça belirtebilirsiniz.Bu belirli lambda ifadesi, ikiye bölündüğünde 1 kalan veren tamsayıları (n) sayar.

Aşağıdaki kod satırı, numbers dizisinde koşulu sağlamayan ilk sayı olduğundan 9 olduğundan dizinin 9'un sol tarafında kalan tüm öğelerini içeren bir dizi üretir:

var firstNumbersLessThan6 = numbers.TakeWhile(n => n < 6);

Bu örnek birden fazla giriş parametrelerini paranteze alarak belirtmeyi gösterir.Yöntem, değeri konumundan daha az olan bir sayı ile karşılaşana dek sayı dizisindeki tüm öğeleri döndürür.Lambda işlecini (=>) büyük veya eşittir işleciyle (>=) karıştırmayın.

var firstSmallNumbers = numbers.TakeWhile((n, index) => n >= index);

Lambda İçinde Tür Çıkarımı

Lambda ifadeleri yazarken genellikle giriş parametreleri için bir tür belirtmeniz gerekmez; derleyici lambda gövdesine, parametrenin temsilci türüne ve C# Dil Belirtimi'nde açıklanan diğer etkenlere göre türü çıkarsayabilir.Standart sorgu işleçlerinin çoğunda ilk giriş kaynak dizisindeki öğelerin türüdür.IEnumerable<Customer> sorguluyorsanız giriş değişkeni, buna ilişkin yöntemlere ve özelliklere erişiminiz olduğu anlamına gelen Customer nesnesi olarak algılanır:

customers.Where(c => c.City == "London");

Lambdalar için genel kurallar şunlardır:

  • Lambda temsilci türüyle aynı sayıda parametre içermelidir.

  • Lambdadaki her giriş parametresi, denk gelen temsilci parametresine dolaylı olarak dönüştürülebilir olmalıdır.

  • Lambdanın (varsa) dönüş değeri örtük olarak temsilcinin dönüş türüne dönüştürülebilir olmalıdır.

Ortak tür sisteminin "lambda ifadesi" için iç kavramı olmadığından kendi içlerindeki lambda ifadelerinin türü olmadığını unutmayın. Ancak bazen bir lambda ifadesinin "türünden" resmi olmayan bir şekilde bahsetmek daha kolaydır.Bu gibi durumlarda, tür lambda ifadesinin dönüştürüldüğü temsilci türüne veya Expression türüne başvurur.

Lambda İfadelerinde Değişken Kapsamı

Lambda'lar, lambda işlevini tanımlayan yöntemin kapsamındaki ya da lambda ifadesini içeren türün kapsamındaki dış değişkenlere (bkz. Anonim Yöntemler (C# Programlama Kılavuzu)) başvurabilir.Bu şekilde tutulan değişkenler, aksi halde kapsam dışına çıkacak ve çöp olarak toplanacak olsalar dahi kullanılmak üzere lambda ifadesinde saklanır.Bir lambda ifadesinde tüketilebilmesi için öncelikle mutlaka bir harici değişken tayin edilmelidir.Aşağıdaki örnek bu kuralları gösterir:

delegate bool D();
delegate bool D2(int i);

class Test
{
    D del;
    D2 del2;
    public void TestMethod(int input)
    {
        int j = 0;
        // Initialize the delegates with lambda expressions.
        // Note access to 2 outer variables.
        // del will be invoked within this method.
        del = () => { j = 10;  return j > input; };

        // del2 will be invoked after TestMethod goes out of scope.
        del2 = (x) => {return x == j; };
      
        // Demonstrate value of j:
        // Output: j = 0 
        // The delegate has not been invoked yet.
        Console.WriteLine("j = {0}", j);        // Invoke the delegate.
        bool boolResult = del();

        // Output: j = 10 b = True
        Console.WriteLine("j = {0}. b = {1}", j, boolResult);
    }

    static void Main()
    {
        Test test = new Test();
        test.TestMethod(5);

        // Prove that del2 still has a copy of
        // local variable j from TestMethod.
        bool result = test.del2(10);

        // Output: True
        Console.WriteLine(result);
           
        Console.ReadKey();
    }
}

Lambda ifadelerindeki değişken kapsam için aşağıdaki kurallar geçerlidir:

  • Tutulan bir değişkenin kullandığı bellek, ona başvuran temsilcinin kullandığı bellek geri kazanılmaya hazır hale gelinceye kadar geri kazanılmaz.

  • Bir lambda ifadesi içinde tanıtılan değişkenler, dış yöntemde görünmez.

  • Lambda ifadesi, kapsayan bir yöntemden alınan ref veya out parametresini doğrudan yakalayamaz.

  • Lambda ifadesindeki bir dönüş ifadesi, kapsayan yöntemin döndürülmesine neden olmaz.

  • Bir lambda ifadesi, atlama bildiriminin hedefi blok dışındaysa, lambda işlevi içinde bir goto bildirimi, break bildirimi ya da continue bildirimi içeremez.Ayrıca, hedef, blok içinde ise lambda işlev bloğu dışında bir deyim olması bir hatadır.

C# Dil Belirtimi

Daha fazla bilgi edinmek için, bkz. C# Dil Belirtimi. Dil belirtimi, C# sözdizimi ve kullanımı için kesin bir kaynaktır.

Özel Kitap Bölümü

Delegates, Events, and Lambda Expressions içindeki C# 3.0 Cookbook, Third Edition: More than 250 solutions for C# 3.0 programmers

Ayrıca bkz.

Başvuru

Anonim Yöntemler (C# Programlama Kılavuzu)

is (C# Başvurusu)

Kavramlar

C# Programlama Kılavuzu

İfade Ağaçları (C# ve Visual Basic)

Diğer Kaynaklar

LINQ (Dil ile Tümleşik Sorgu)

Visual Studio 2008 C# Örnekleri (bkz. LINQ Örnek Sorguları Dosyaları ve XQuery programı)

Yinelemeli lambda ifadeleri