CodeGym /Kurslar /C# SELF /Lambda-ifadələr üçün tip kimi delegate-lər

Lambda-ifadələr üçün tip kimi delegate-lər

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

1. Giriş

Təsəvvür edin ki, sizin qəhvə maşınınız var. Adətən o sadəcə qəhvə bişirir və heç kəsi narahat etmir, amma bəzən şef deyir: «Zəhmət olmasa, qəhvə bişdikdən sonra “Hazır!” deyə qışqırarsan?» — və burada bir konfiqurasiya lazımdır. Qəhvə maşınını yenidən yazmırsınız. Sadəcə onun sonunda icra edəcəyi bir funksiyanı yaradırsınız.

C#-da bu rolu delegate-lər oynayır — onlar metodlara kod parçalarını (metodlar, lambda-lar və ya anonim metodlar) ötürməyə imkan verir ki, həmin metod onları lazım olan vaxt çağırsın. Sadə dillə desək, delegate müəyyən imzaya malik metodlara istinadları saxlaya bilən tipdir.

Delegate-in təyini

C#-da delegate delegate açar sözü ilə təyin olunur. Məsələn:

// Delegate, int qəbul edib bool qaytaran metodlara istinad edir
public delegate bool PredicateInt(int x);

İndi PredicateInt tipində dəyişən hər hansı bir metodu (və ya lambdanı!) istinad edə biləcək, hansı ki bir int qəbul edib bool qaytarır.

Delegate-lər nə üçün lazımdır?

  • Loqikanı arqument kimi ötürmək (məsələn, sortlama, filtrləmə, event emalı üçün)
  • Event-lərə abunə olmaq (bunlar barədə sonra danışacağıq)
  • Callback-lərin həyata keçirilməsi
  • Çağıran tərəf davranışın bir hissəsini müəyyən edən çevik API-lər

Sadə vizual sxem

Delegate tipi İmza Çağırış nümunəsi
Action
void()
Action act = () => ...
Func<int>
int()
Func<int> f = () => 42
Func<int, bool>
bool(int)
Func<int, bool> p = x => x > 0

2. Lambda necə delegate-ə çevrilir

Sintaksis

Məsələn, x => x > 5 kimi lambda yazanda, əslində delegate obyekti yaradırsınız. Lambda boşluqda «yaşamır»: ona mütləq bir tip lazımdır (kimsə onun parametrlər dəstini və qaytarılan tipini bilməlidir). Buna görə də C#-da lambda-ifadə həmişə kontekstdən asılı olaraq dolayısı ilə (və ya açıq şəkildə) delegate-ə çevrilir.

Nümunə 1: Delegate-in metoda bağlanması

// Explicit delegate təyini
public delegate bool MyPredicate(int number);

class Program
{
    static void Main()
    {
        // Lambda-nı MyPredicate tipində dəyişənə təyin edirik
        MyPredicate isEven = x => x % 2 == 0;

        Console.WriteLine(isEven(4));  // true
        Console.WriteLine(isEven(7));  // false
    }
}

Nümunə 2: Standart delegate-lərin istifadəsi

C# bir sıra ümumi delegate-lər təqdim edir: Action, Func<>, Predicate<>. Onlar demək olar ki, lambda yazdığınız hər yerdə istifadə olunur.

// Func<int, bool> istifadə edirik
Func<int, bool> isPositive = number => number > 0;
Console.WriteLine(isPositive(-5)); // false

3. Standart delegate-lər: Func, Action, Predicate

Func<...>

Nəsnə qəbul edib nəsə qaytaran metodlar üçün istifadə olunur.

İmza:
— Sonuncu tip qaytarılan dəyərdir, ondan əvvəlkilər parametr tipləridir, məsələn:
Func<int, string> — int qəbul edir, string qaytarır

Func<int, string> intToString = number => "Sayı: " + number;
Console.WriteLine(intToString(7)); // "Sayı: 7"

Action<...>

Heç nə qaytarmayan (void) əməliyyatlar üçün istifadə olunur.

Action<string> printHello = name => Console.WriteLine("Salam, " + name + "!");
printHello("Vasiliy"); // "Salam, Vasiliy!"

Predicate<T>

Əslində Func<T, bool>-un qısaldılmış variantıdır. Obyekt üzərində məntiqi yoxlama tələb olunan zaman istifadə olunur (true/false).

Predicate<int> isOdd = x => x % 2 != 0;
Console.WriteLine(isOdd(3)); // true

Vizual xatırlatma

Delegate İmza Tətbiq
Func<T1, TResult>
Result(T1)
Transformasiya, proyeksiya
Action<T1>
void(T1)
Yan-effektlər, çıxış
Predicate<T>
bool(T)
Filtrləmə, axtarış

Lambda-ifadəsi üçün hansı delegate tipi seçilməlidir?

  • Əgər qaytarılan dəyər gözlənilirsə, Func<...> götürün
  • Əgər metod heç nə qaytarmırsa (void), Action<...> istifadə edin
  • Əgər məntiqi yoxlama lazımdırsa, Predicate<T> istifadə edin

Nümunə: Siyahını filtrləmə

List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6 };

// Predicate<int> gözlənilir
List<int> evenNumbers = numbers.FindAll(x => x % 2 == 0);
Console.WriteLine(string.Join(", ", evenNumbers)); // 2, 4, 6

4. Faydalı nüanslar

Lambda-ifadələr və kolleksiya metodları: içində nə baş verir?

Kolleksiya metodunu çağıranda lambda ötürsəniz, məsələn:

var adults = users.Where(u => u.Age >= 18);

Where metodu arqument kimi Func<T, bool> tipini gözləyir. Yəni sizin u => u.Age >= 18 lambdanız kompilyator tərəfindən həmin tipdə delegate obyektinə çevrilir.

Blok-sxem: bu necə işləyir


Sizin lambda         -->      C# kompilyatoru        -->     Delegate obyekti (Func<T, bool>)
(u => u.Age >= 18)          [tip məlumdur]                (Where() içində çağırıla bilən)

Tiplə bağlı daha detallı: type inference

Adətən delegate tipi kontekstdən avtomatik çıxarılır. Məsələn, List<T>.Find metodu Predicate<T> gözlədiyi üçün kompilyator parametrin tipini metodun imzasından bilir.

List<string> words = new List<string> { "one", "two", "three" };
var result = words.Find(word => word.Length == 5); // Find Predicate<string> gözləyir
Console.WriteLine(result); // "three"

Əgər kontekst aydın deyilsə, kompilyatora kömək etmək lazım gəlir:

// Tipi açıq şəkildə göstəririk
Func<int, bool> check = x => x > 10;

Delegate qaytaran metodlar: funksiyalar fabriki

Bəzən metodlar delegate qaytara bilər — yəni «funksiya fabrikləri» yaratmaq olar. Bu dinamik davranış yaratmaq üçün rahatdır.

// Delegate (lambda) qaytaran funksiya
Func<int, int> GetMultiplier(int factor)
{
    return x => x * factor;
}

var times3 = GetMultiplier(3);
Console.WriteLine(times3(5)); // 15

Bu ona görə işləyir ki, lambda (x => x * factor) xarici kontekstdən factor dəyişənini tutur (closure/bağlama) və Func<int, int> tipində obyekt kimi qaytarılır.

5. Delegate-lər və lambda-larla bağlı səhvlər və anlaşılmazlıqlar

İmzaların üst-üstə düşməməsi

Əgər parametrlər və ya qaytarılan dəyər uyğun gəlmirsə, kompilyator lambda-nı delegate-ə təyin etməyə imkan verməyəcək.

Func<int, int> f = x => "String qaytara bilməzsən!"; // Kompilyasiya səhvi

Lambda-nı delegate olmadan istifadə etməyə çalışmaq

Sadəcə lambda yazıb onu tipsiz çağırmaq olmaz:

// Bu işə yaramayacaq - kompilyator tipi çıxara bilməz
// var myFunc = x => x * 2; // CS0815 səhvi
// myFunc(10);

İşləməsi üçün tipi açıq göstərmək və ya kontekst vermək lazımdır:

Func<int, int> myFunc = x => x * 2;
Console.WriteLine(myFunc(10)); // 20

Action, Func və Predicate arasında qarışıqlıq

Bəzən yanlış delegate tipi seçərək imza uyğunsuzluğu alınır. Sadə qaydanı yadda saxlayın: nəticə varsa — Func, heç nə qaytarılmırsa — Action (void), məntiqi cavab lazımdırsa — Predicate<T> (bool).

2
Tapşırıq
C# SELF, səviyyə, dərs
Bağlanıb
Lambda ifadəsi üçün delegatın yaradılması və istifadəsi
Lambda ifadəsi üçün delegatın yaradılması və istifadəsi
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION