CodeGym /Kurslar /C# SELF /Delegatlarla hadisələrin yaradılması (

Delegatlarla hadisələrin yaradılması ( eventdelegate)

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

1. Giriş

Beləliklə, C# kontekstində "hadisə" (event) dedikdə, bir və ya bir neçə obyektə nəyinsə baş verdiyini təhlükəsiz şəkildə bildirməyə imkan verən mexanizmi nəzərdə tuturuq. Hadisələr sehr deyil: altında delegatlar (açar söz delegate) yerləşir və əlavə qoruma var ki, səhv istifadə olmasın.

YouTube kanalına abunəlik misalını təsəvvür et. Kanalın (hadisənin sahibi obyektin) "Abunə ol" düyməsi var — hər bir izləyici (başqa obyekt) onu sıxıb abunəçilər siyahısına (delegat-işləyicilərə) düşə bilər. Müəllif yeni video yükləyəndə (hadisəni çağıranda) bildirişləri yalnız abunəçilər alır, və kanal sahibi qərar verir ki, nə vaxt bu baş verəcək. Vacib məqam: izləyicilər abunə ola və ya abunəliyi ləğv edə bilərlər, amma bildirişi özləri göndərə bilməzlər — bu hüquq yalnız kanal sahibinə məxsusdur.

Biraz rəsmi sintaksis


// Hadisə işləyicisinin "forması"nı müəyyən edən delegatın elan edilməsi
public delegate void SimpleEventHandler();

// Delegat əsasında hadisənin elan edilməsi
public event SimpleEventHandler SomethingHappened;

Hər şey sadədir: event — hadisəni elan edən açar sözdür, hadisənin tipi həmişə delegatla müəyyən edilir.

2. İlk sadə nümunə: "Düymə basıldı!" hadisəsi

1-ci addım. Hadisə işləyiciləri üçün delegatı təyin edirik


// Hadisə işləyicisi: heç nə qaytarmır, parametr qəbul etmir
public delegate void ButtonClickHandler();

2-ci addım. Hadisəsi olan sinif


public class Button
{
    // Hadisə: abunə olmaq və abunəliyi ləğv etmək olar, amma xaricdən onu çağırmaq mümkün deyil
    public event ButtonClickHandler Click;

    // "Düyməni basan" metod
    public void Press()
    {
        Console.WriteLine("Düymə basıldı!");
        // Hadisəni çağırmaq: bütün abunəçiləri xəbərdar etmək
        Click?.Invoke();
    }
}

Qeyd et: hadisə delegat əsasında elan olunub və Press metodunda hadisə ?.Invoke() vasitəsilə çağırılır. Niyə belə? Çünki hadisə boş ola bilər (heç kim abunə olmayıb), onda Click null-dır. Təhlükəsiz çağırış operatoru yalnız abunəçilər varsa işləməyi təmin edir.

3-cü addım. Hadisəyə abunəlik və kodun işə salınması


// İstifadə nümunəsi
public class Program
{
    public static void Main()
    {
        var button = new Button();

        // "Dinləyici" əlavə edirik (hadisəyə abunə oluruq)
        button.Click += OnButtonClicked;
        button.Click += () => Console.WriteLine("Daha bir işləyici işləyir!");

        button.Press(); // Düymənin basılmasını simulyasiya edirik

        // Hadisədən abunəliyi ləğv etmək olar
        button.Click -= OnButtonClicked;
        button.Press();
    }

    // Normal hadisə işləyicisi
    public static void OnButtonClicked()
    {
        Console.WriteLine("İşləyici: Düymə basıldı!");
    }
}

Birinci basmada hər iki işləyici işə düşəcək, ikinci basmada isə yalnız lambda işləyicisi.

3. Hadisə ilə delegat arasındakı fərq

Delegata sərbəst şəkildə dəyər təyin etmək və hətta abunəçilər siyahısını tam əvəz etmək olar — kimsə belə yazı bilər: button.Click = null və əvvəlki bütün abunəliklər "uçub".

Hadisədə vəziyyət fərqlidir — o obyektə daha sıx bağlıdır. Yalnız hadisəni elan edən sinfin sahibi onu birbaşa çağırmağa bilər (məsələn, sinifin içindən Click()). Hər hansı başqa kod yalnız += ilə abunə ola və -= ilə abunəliyi ləğv edə bilər, amma hamısını "sıfırlaya" bilməz. Bu, enkapsulyasiyanı qoruyur və abunəlik sistemini "sındırmaq"dan qoruyur.

4. İmza: hadisələr üçün delegat tipləri, parametrlər

.NET-də ənənə belədir: hadisə işləyicisi iki parametr alır — object sender (hadisəni kim çağırdı) və hadisə arqumentləri (EventArgs). Tövsiyə olunur ki, EventHandler və ya EventHandler<TEventArgs> delegatlarından istifadə edəsiniz.

Nümunə: parametrlərlə delegat


public delegate void ButtonClickHandler(object sender, EventArgs e);

EventArgs — əlavə məlumat ötürmək üçün baza sinifdir. Daha çox məlumat lazım olsa, öz törəmənizi yaradırsınız.

Bunu düyməmizə tətbiq edək


// Hadisə arqumentləri sinfi
public class ButtonClickEventArgs : EventArgs
{
    public string UserName { get; }

    public ButtonClickEventArgs(string userName)
    {
        UserName = userName;
    }
}

public class Button
{
    public event EventHandler<ButtonClickEventArgs> Click;

    public void Press(string userName)
    {
        Console.WriteLine("Düymə basıldı!");
        Click?.Invoke(this, new ButtonClickEventArgs(userName));
    }
}

public static void Main()
{
    var button = new Button();
    button.Click += OnButtonClicked;

    button.Press("Vasiliy");
}

public static void OnButtonClicked(object sender, ButtonClickEventArgs e)
{
    Console.WriteLine($"İstifadəçi {e.UserName} düyməni sıxdı!");
}

5. Vizual sxem: hadisənin necə işlədiyi


+-------------+
|  İstifadəçi |
+-------------+
      |
      v
+--------------+
| Button.Press |
+--------------+
      |
      v
+-----------------+         +------------------------+
|  Click çağırışı |----->---|   Abunəçi 1           |
+-----------------+         +------------------------+
      |                     |   İşləyicini icra et     |
      v                     +------------------------+
+-----------------+         +------------------------+
|   Əgər abunəçi  |----->---|   Abunəçi 2           |
+-----------------+         +------------------------+
      :                     |   İşləyicini icra et     |
      v                     +------------------------+

Button.Press hadisəni çağırır; abunəçilərin işləyiciləri sırayla icra olunur.

6. Faydalı nüanslar

.NET-də tövsiyə edilən hadisə forması

Kodun kitabxanalarla və alətlərlə uyğunluğu üçün EventHandlerEventHandler<TEventArgs> istifadə edin. Bu yanaşma hadisələrin inkişafını asanlaşdırır: EventArgs-lərə yeni xassələr əlavə edə bilərsiniz və abunəçiləri qırmazsınız.

Sənədləşmə: EventHandler, event.

Hadisələr vs delegatlar

Bir komponenti konkret metoda bağlamaq lazımdırsa — delegat (delegate) kifayətdir. Amma proqramın müxtəlif hissələrinin istənilən vaxt abunə olub çıxması lazımdırsa — hadisə (event) istifadə edin.

7. Hadisələrin yaradılmasında tipik səhvlər və narahat məqamlar

Səhv №1: hadisəni null üçün yoxlamadan çağırmaq. Hadisənin abunəçisi yoxdursa, birbaşa onu çağırmaq NullReferenceException-a gətirib çıxaracaq. Təhlükəsiz çağırışdan istifadə edin:


Click?.Invoke(...);

Səhv №2: hadisəni sinifdən kənar çağırmağa çalışmaq. Hadisəni yalnız onu elan edən sinifin daxilində qaldırmaq (çağırmaq) olar. Başqa sinifdən çağırmağa çalışsanız, kompilyator xəta verəcək — bu, enkapsulyasiyanı qorumaq üçündür.

Səhv №3: eyni işləyiciyə bir neçə dəfə abunə olmaq. Bir işləyici bir neçə dəfə abunə olunubsa, o qədər dəfə çağırılacaq. Bu abunə mexanizminin xüsusiyyətidir. += təkrarlanmasına və düzgün -= ilə abunəliyin ləğvinə diqqət edin.

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