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
  
    istifadə edirik Func
   
     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
  
    intToString = number => "Sayı: " + number; Console.WriteLine(intToString(7)); // "Sayı: 7" 
  

Action<...>

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

Action
  
    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
  
    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
  
    numbers = new List
   
     { 1, 2, 3, 4, 5, 6 }; // Predicate
    
      gözlənilir List
     
       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
  
   ) (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
  
    words = new List
   
     { "one", "two", "three" }; var result = words.Find(word => word.Length == 5); // Find Predicate
    
      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
  
    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
  
    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
  
    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
  
    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).

Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION