1. Giriş
Gəlin xatırlayaq: hadisə — bu sizin kodun abunəçiləri "çağıracağı" haqında verilən publik müqavilədir, yəni nəyisə vacib baş verəndə xəbər verəcəyinə söz verir. Keçən mühazirələrdə nümunələrdə belə elan görmüş ola bilərsiniz:
public event Action<string> MessageSent;
Və ya hətta:
public delegate void MyHandler(int value);
public event MyHandler SomethingHappened;
Bu işləyir, amma belə yanaşma bir sıra problemlər doğurur — metod imzalarının uyğunsuzluğundan tutmuş, hadisənin kimdən gəldiyini və nə baş verdiyini bilməməyə qədər. Təsəvvür elə, klaviaturada hər düyməni vuranda düymə təsadüfi işləsəydi, hər dəfə fərqli nəticə versəydi — eyni proqramda eyni tapşırıq üçün. Məsələn, oyun oynayırsan və space basırsan. Bir an qabaq bu tullanmaq idi, indi isə gözlənilmədən inventarı açır. Kosmar, standart deyil!
.NET-də hadisələr üçün müəyyən mənada Konstitusiya var — bu, handler imzası və hadisə ilə ötürülən məlumatın strukturu barədə razılaşmadır. Kanonik stil belə görünür:
void Handler(object sender, EventArgs args);
Tanış sətrdir? O, hər yerdə rast gəlinir: WinForms düymə kliklərindən tutmuş ASP.NET sistem hadisələrinə və hətta üçüncü tərəf kitabxanalarına qədər.
2. EventHandler və EventArgs nədir
Əsas ideya: hər hadisə iki şeyi bildirir:
- Hadisəni kim çağırdı? sender
- Nə baş verdi? EventArgs — əlavə məlumat
C# aləmində bu belə ifadə olunur:
public delegate void EventHandler(object sender, EventArgs e);
- object sender — hadisəni başladanın göstəricisidir. Bu hər nə ola bilər — sadəcə this.
- EventArgs e — hadisə haqqında əlavə məlumat saxlayan obyekt. Sadə senarilər üçün EventArgs.Empty istifadə olunur, mürəkkəb hallar üçün isə öz EventArgs törəmələrinizi yaradırsınız.
Qəribə fakt
Rəsmi .NET tövsiyələrinə görə publik API-lərdə hadisənin imzası (object sender, EventArgs e) olmalıdır. Əgər sizdə sender və EventArgs olmayan hadisə görsəniz — bu, çox güman müəllifin sadələşdirdiyi versiyasıdır, amma kanonik .NET stili deyil.
Bir standartın böyük faydası
Bir standartla hadisələri loglamaq, test etmək, universal abunə olmaq və sistemi genişləndirmək daha asandır. WinForms, WPF, ASP.NET mənbələrini açın — eyni şablonu görəcəksiniz.
3. Standart hadisə şablonundan necə istifadə etmək
1. Daxili delegatdan EventHandler istifadə edək
Öz delegatınızı elan etmək əvəzinə hazırdan istifadə edin:
public event EventHandler SmthHappened;
İndi handler həmişə eyni cür görünür:
private void OnSmthHappened(object sender, EventArgs e)
{
// Hadisəyə reaksiya məntiqi
}
Abunə olmaq hələ də sadədir:
myObj.SmthHappened += OnSmthHappened;
Vacib: əgər hadisə əlavə məlumat ötürmürsə, EventArgs.Empty istifadə edin.
2. Öz hadisə arqumentlərinizi yaratmaq
Məlumat (hesablamanın nəticəsi, fayl adı, səhv) ötürmək lazımdırsa, EventArgs-dən törəmə yaradın:
public class CalculationEventArgs : EventArgs
{
public double Result { get; }
public CalculationEventArgs(double result) => Result = result;
}
Sonra generik universal delegatdan — EventHandler<TEventArgs> istifadə edirik:
public event EventHandler<CalculationEventArgs> CalculationFinished;
Və handler artıq sizin arqument tipinizi qəbul edir:
private void OnCalculationFinished(object sender, CalculationEventArgs e)
{
Console.WriteLine($"Hesablama bitdi. Nəticə: {e.Result}");
}
4. Tətbiq nümunəsi
Tədris layihəmizi inkişaf etdirək — misal üçün kalkulyatorumuz var, toplama və çıxma əməliyyatları edir və əməliyyatın bitməsini hadisə vasitəsilə bildirir.
Minimal nümunə
public class Calculator
{
public event EventHandler<CalculationEventArgs> CalculationPerformed;
public void Add(int a, int b)
{
int result = a + b;
// Hadisəni "atırıq"
CalculationPerformed?.Invoke(this, new CalculationEventArgs(result));
}
}
public class CalculationEventArgs : EventArgs
{
public int Result { get; }
public CalculationEventArgs(int result) => Result = result;
}
Abunə oluruq və istifadə edirik:
var calc = new Calculator();
calc.CalculationPerformed += (sender, e) =>
{
Console.WriteLine($"Əməliyyatın nəticəsi: {e.Result}");
};
calc.Add(10, 20);
// Çap edəcək: Əməliyyatın nəticəsi: 30
Budur bütün "standart": handler həmişə göndərən obyekt və arqument obyekti qəbul edir — universal və aydın.
5. Faydalı nüanslar
Hadisənin çağırılmasının enkapsulyasiyası: yaxşı stil
.NET-də hadisəni çağırma məntiqini On prefiksi olan ayrı qorunan metoda çıxarmaq adətdir:
protected virtual void OnCalculationPerformed(CalculationEventArgs e)
{
CalculationPerformed?.Invoke(this, e);
}
Və əməliyyatların içində ("Add", "Subtract" və s.) sadəcə bu metod çağırılır:
public void Add(int a, int b) => OnCalculationPerformed(new CalculationEventArgs(a + b));
Belə stil törəmələrə hadisənin davranışını override etməyə imkan verir və hadisəni çağırmağı unutmaq ehtimalını azaldır.
Şəkl: .NET standart hadisəsinin quruluşu
graph LR
A[Obyekt-nəşriyyatçı] -- "event EventHandler/ EventHandler<TEventArgs>" --> B[Abunəçilər siyahısı]
B -- "Metod-handler (object sender, EventArgs e)" --> C[Hadisəyə reaksiya]
A -- "this (göndərən)" --> C
A -- "EventArgs (məlumat)" --> C
Hadisə elan variantlarının müqayisəsi
| Yanaşma | İnisiyatorun ötürülməsi (sender) | Arqumentlərin ötürülməsi | Universalıq | .NET-də istifadə |
|---|---|---|---|---|
|
Yox | Bəli | Aşağı | Yox |
|
Bəli | Bəli | Orta | Yox (nadir) |
|
Bəli | Yox (EventArgs) | Yüksək | Bəli, standart |
|
Bəli | Bəli (MyArgs) | Çox yüksək | Bəli, standart |
İşə yarayan fayda — müsahibələrdə və real kodda
Standart hadisə şablonundan istifadə etmək .NET inkişafçısı üçün must-have-dir. Müsahibədə sizdən çox ehtimal ki EventHandler və bir neçə sender/EventArgs haqqında soruşacaqlar. Action<T> tipli hadisə çox vaxt "sadələşdirilmiş" kimi qəbul olunur.
Real layihələrdə belə yanaşma əməkdaşlığı, test etməni, genişlənə bilməyi və kodun dəstəyini asanlaşdırır. Üçüncü tərəf kitabxanaları (logging, profilerlər) standart formadan istifadə olunanda daha asan inteqrasiya olunur.
Hadisə çağırma blok-sxemi
flowchart TD
subgraph A[Çap edən sinif]
C1((Obyekt))
C2[Hadisəni çağıran metod]
C3["event EventHandler<MyArgs>"]
end
subgraph B[Abunəçi sinif]
D1((Abunə))
D2["Hadisə handleri (object sender, MyArgs args)"]
end
C1 -- Çağırır --> C2
C2 -- "Invoke(this, args)" --> C3
C3 -- "Məlumatlandırır" --> D1
D1 -- "Çağırır" --> D2
6. Məsləhətlər, nüanslar və tipik səhvlər
1. Handler imzası. Action<int> tipli hadisə etmək istəyirsən? Bu cazibədardır, amma sən sender və ekosistemlə uyğunluğu itirirsən.
2. Arqumentlərin ötürülməsi. EventArgs-i adi parametrlərlə qarışdırma. Handlerə bütün məlumatları arqument obyektində ötür.
3. Arqumentlər üçün null istifadəsi. null əvəzinə əlavə məlumat yoxdursa EventArgs.Empty istifadə et.
4. Zəif tipli yanaşma. Bir "hər şeyi qəbul edən" EventHandler etmə və ora hər şeyi yığma. Hər hadisə üçün ayrıca törəmə sinif yarat — oxunaqlılıq və etibarlılıq artır.
5. Hadisəni çağırmaqda səhvlər. Həmişə abunəçilərin olub-olmadığını yoxla: SomeEvent?.Invoke(this, e). Abunəçi yoxdursa, hadisə referansı null olur.
6. Enkapsulyasiyanın pozulması. Hadisəni nəşriyyatçı sinifdən xaric çağırma. Hadisə yalnız abunə/abonəlikdən çıxmaq üçündür; çağırış On... metodu vasitəsilə sinif daxilində edilməlidir.
GO TO FULL VERSION