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);
}
GO TO FULL VERSION