CodeGym /Kurslar /C# SELF /Lambda-ifadələri event

Lambda-ifadələri event və callback üçün

C# SELF
Səviyyə, Dərs
Mövcuddur

1. Giriş

C#-da (və .NET-də ümumiyyətlə) eventlər obyektlərin bir-biri ilə ünsiyyət qurma yollarından biridir. Məsələn, sizin bir düyməniz var və onun vurulması nəyəsə başlamalıdır. Siz ayrıca metod elan edib, sonra o metodu event-ə əl ilə abunə edə bilərdiniz... Amma çox vaxt istəyirsən ki, "reaksiyanı birbaşa burda təsvir edəsən", loqikanı faylın müxtəlif hissələrinə yaymamaq üçün.

Lambda-ifadələr bu işi əla görür — event-ə abunə olduğunuz eyni yerdə reaksiyanı yazmağa imkan verir. Minimum mərasim — maksimum fayda.

Eyni söz callback-lərə də aiddir: bəzən metoda müəyyən bir loqika verirsiniz ki, "sonra" icra olunsun, məsələn, əməliyyat bitəndə. Yenə də — lambda-ifadələr bunu sadə və aydın edir: bütün lazım olan loqika elə çağırış yerindədir.

Eventlər və callback-lər: qısa məqamlar və lambda-nın harada lazım olduğu

Event — obyekt üzərində "bura kiminsə abunə olub nəsə edə biləcəyi" üçündür.

Callback (geri çağırış) — "mən sənə indi bir funksiyanı verirəm, və sən onu lazım olanda çağır". Çox vaxt "müraciət et — biz zəng edəcəyik" fikrinə oxşayır.

Delegate-lərlə və event-lərlə tanış olanda belə sintaksis görmüş ola bilərsiniz:

button.Click += MyButtonClickHandler;

Burada MyButtonClickHandler — bir yerdə elan edilməli xüsusi metoddur. Amma əgər loqika sadədirsə, yalnız bir neçə sətrə sığdırmaq istəyirsən, metodlar çox yaratmaq lazım deyil.

Burada səhnəyə lambda-lar daxil olur:

button.Click += (sender, args) => { Console.WriteLine("Düymə basıldı!"); };

Konkis, aydın, birbaşa burada!

2. Lambda-lar event handler kimi: sadədən maraqlıya

Sadə forma: lampanı bir dəfə yandırdıq — konsola yazdı

Tutaq ki, bizim Button sinifimiz var və onun Click eventinə reaksiya vermək istəyirik.

// Gəlin belə bir düymə təsəvvür edək:
public class Button
{
    public event EventHandler? Click;

    public void SimulateClick() // Nümunə üçün: proqramatik "vururuq"
    {
        // Kiminsə abunə olmasını yoxlayırıq və çağırırıq
        Click?.Invoke(this, EventArgs.Empty);
    }
}

İndi bu düyməni istifadə edək:

var button = new Button();

// Lambda ilə düymənin eventinə abunə oluruq!
button.Click += (sender, args) =>
{
    Console.WriteLine("Yey! Düymə basıldı!");
};

button.SimulateClick(); // => Yey! Düymə basıldı!

İzahedici:
— =>-dən sonra olan hər şey sizin "mini-funksiyanız"ın bədənidir, event baş verəndə çağırılacaq.
— Handler-in ömrünü düşünməyə ehtiyac yoxdur: o, abunə olduğu müddətcə yaşayır (+=). Vacib: əgər lambda xaricdən dəyişənləri capture edirsə və siz eventdən ayılmırsınızsa, bu yaddaş sızmasına səbəb ola bilər.

Xarici dəyişənləri capture edən lambda-handler

int clickCount = 0;

button.Click += (sender, args) =>
{
    clickCount++;
    Console.WriteLine($"Düymə artıq {clickCount} dəfə basılıb!");
};

button.SimulateClick(); // => Düymə artıq 1 dəfə basılıb!
button.SimulateClick(); // => Düymə artıq 2 dəfə basılıb!

Nə baş verir:
Lambda xaricdəki clickCount dəyişəni "capture" edir və çağırışlar arasında onun dəyərini xatırlayır.

3. Lambda-ifadələrinin callback kimi tətbiqi

Geri çağırış adətən bəzi kodun sizin funksiyanızı sonra çağırmalı olduğu hallarda istifadə olunur — məsələn, uzun müddət aparılan iş bitdikdə.

Lambda-nı callback kimi ötürmək

Tutaq ki, bizim metodumuz var və o, delegate və ya lambda qəbul edir:

void DoWork(Action callback)
{
    Console.WriteLine("İş başlayır...");
    // İşin simulyasiyası
    System.Threading.Thread.Sleep(500); // (Real tətbiqlərdə belə etmək olmaz, bu bloklayıcı əməliyyatdır!) 
    callback(); // İşdən sonra callback çağırılır
}

DoWork(() => Console.WriteLine("İş tamamlandı!"));

Nəticə:
Əvvəl konsolda "İş başlayır...", sonra isə "İş tamamlandı!"

Parametrləri olan lambda-lar da ötürmək olar:

void Calculate(int a, int b, Action<int> onResult)
{
    int sum = a + b;
    onResult(sum);
}

Calculate(5, 8, result => Console.WriteLine($"Nəticə: {result}"));

4. Lambda-lardan istifadə zamanı tipik səhvlər

Event-dən ayılmamaq

Lambda ilə event-ə abunə olarkən adətən "handler adı" olmur, buna görə sonra asanlıqla ayılmaq çətindir:

button.Click += (s, e) => Console.WriteLine("...");
button.Click -= ??? // Buraya lambda necə ötürək? Əgər saxlanmayıbsa, mümkün deyil.

Əgər mütləq ayılmaq lazımdırsa — lambdanı dəyişənə saxlayın:

EventHandler handler = (s, e) => Console.WriteLine("...");
button.Click += handler;
// ...sonra
button.Click -= handler;

Bu uzunömürlü obyektlər üçün vacibdir: ayılmasanız, istinad qalacaq və bəlkə yaddaş sızmasına gətirib çıxaracaq.

Dövrün dəyişəninin capture edilməsi

Klassika: dövr içində event-ə abunə olmaq:

for (int i = 0; i < 3; i++)
    button.Click += (s, e) => Console.WriteLine(i); // Bütün lambda-lar eyni i-ni "xatırlayır"

Müasir C# versiyalarında bu davranış foreach üçün düzəldilib, amma for üçün bəzən incə məqamlar ola bilər — capture edilmiş dəyişənlərlə həmişə diqqətli olun!

Hər lambda öz dəyərini xatırlasın istəyirsinizsə — lokal nüsxə yaradın:

for (int i = 0; i < 3; i++)
{
    int localI = i;
    button.Click += (s, e) => Console.WriteLine(localI);
}
2
Tapşırıq
C# SELF, səviyyə, dərs
Bağlanıb
Dəyişənlərin tutulması ilə klik sayğacı
Dəyişənlərin tutulması ilə klik sayğacı
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION