Event PesananBaru pada bab sebelumnya mengirim satu string, tetapi notifikasi pesanan nyata membawa lebih banyak data: nomor, total, dan nama pembeli. Konvensi .NET menuntut setiap event mengirim dua hal ke handler: object sender yang menunjuk sumber pemicuan, dan objek turunan EventArgs yang membawa data terstruktur. Tipe EventHandler<TEventArgs> adalah delegate bawaan yang mengikat kedua aturan itu.

Konvensi ini lahir dari kebutuhan nyata: handler hampir selalu butuh tahu sumber kejadian untuk menghindari pemrosesan ulang, dan butuh data terstruktur agar tidak mengurai string manual. EventHandler<TEventArgs> membakukan keduanya dalam satu tipe delegate bawaan, sehingga seluruh API .NET berbagi bentuk signature yang sama.

EventArgs dan EventHandler #

csharp
class NotifikasiPesananEventArgs : EventArgs
{
    public string Nomor { get; }
    public int Total { get; }

    public NotifikasiPesananEventArgs(string nomor, int total)
    {
        Nomor = nomor;
        Total = total;
    }
}

class NotifikasiPesanan
{
    public event EventHandler<NotifikasiPesananEventArgs> Diterima;

    public void Proses(string nomor, int total)
    {
        OnDiterima(new NotifikasiPesananEventArgs(nomor, total));
    }

    private void OnDiterima(NotifikasiPesananEventArgs e)
    {
        Diterima?.Invoke(this, e);
    }
}

NotifikasiPesanan notifikasi = new();
notifikasi.Diterima += (pengirim, e) =>
    Console.WriteLine($"{e.Nomor} | total {e.Total} | dari {pengirim.GetType().Name}");

notifikasi.Proses("INV-404", 375000);

Output yang Dihasilkan:

text
INV-404 | total 375000 | dari NotifikasiPesanan

Bedah Kode Baris per Baris #

Mari kita telaah kode di atas:

  1. Baris 1-13: Class argumen mewarisi EventArgs dan membawa dua properti read-only, Nomor dan Total, yang diisi lewat constructor.
  2. Baris 16: Event bertipe EventHandler<NotifikasiPesananEventArgs>; parameter pertama handler adalah object sender, parameter kedua adalah data event.
  3. Baris 18-21: Method Proses membungkus pemicuan ke OnDiterima. Pola ini memudahkan subclass menimpa perilaku pemicuan lewat virtual bila diperlukan.
  4. Baris 23-26: OnDiterima meneruskan this sebagai sender, sehingga handler dapat menelusuri objek penerbit.
  5. Baris 29-30: Lambda handler membaca e.Nomor dan e.Total dari data event, lalu memanggil GetType() pada sender untuk menampilkan nama class penerbit.

Perhatikan juga bahwa NotifikasiPesananEventArgs bersifat read-only: data diisi lewat constructor, dan propertinya tanpa setter publik. Praktik ini mencegah satu subscriber mengubah data event di tengah perjalanan menuju handler berikutnya, dan kebiasaan yang sama berlaku untuk semua class turunan EventArgs yang kita buat.