Event memiliki siklus hidup yang berulang di setiap fitur yang memakainya: dideklarasikan, diisi subscriber, dipicu, lalu ditinggalkan subscriber. Urutan ini terlihat sepele, tetapi sebagian besar bug event berasal dari tahap yang terlewat, misalnya handler terpanggil dua kali atau tidak terpanggil sama sekali. Bab ini menelusuri keempat tahap pada satu alur pembayaran kasir.
Keempat tahap tidak selalu berurutan di dalam satu method: pada aplikasi UI, langganan biasanya terjadi saat halaman dibuka dan pelepasan saat halaman ditutup. Urutan logikanya tetap sama, dan bab Event Memory Leaks akan menunjukkan akibat nyata bila tahap keempat terlewat.
Empat Tahap Siklus Event #
- Deklarasi: publisher menuliskan event; backing field bernilai
nullkarena belum ada subscriber. - Langganan: subscriber mendaftar handler lewat
+=. - Pemicuan: publisher memanggil
Invoke; seluruh handler berjalan berurutan. - Pelepasan: subscriber melepas handler lewat
-=, dan pemicuan berikutnya tidak lagi menjangkau handler tersebut.
class MesinKasir
{
public event Action<string> TransaksiSelesai;
public void Bayar(string nomor)
{
Console.WriteLine($"Pembayaran {nomor} diproses");
TransaksiSelesai?.Invoke(nomor);
}
}
MesinKasir kasir = new();
Console.WriteLine("Tahap 1: event dideklarasikan, belum ada subscriber");
void CatatKuitansi(string nomor) => Console.WriteLine($"Kuitansi {nomor} dicetak");
kasir.TransaksiSelesai += CatatKuitansi;
Console.WriteLine("Tahap 2: subscriber mendaftar lewat +=");
kasir.Bayar("TRX-501");
Console.WriteLine("Tahap 3: publisher memicu event, handler dieksekusi");
kasir.TransaksiSelesai -= CatatKuitansi;
Console.WriteLine("Tahap 4: subscriber melepas diri lewat -=");
kasir.Bayar("TRX-502");Output yang Dihasilkan:
Tahap 1: event dideklarasikan, belum ada subscriber
Tahap 2: subscriber mendaftar lewat +=
Pembayaran TRX-501 diproses
Kuitansi TRX-501 dicetak
Tahap 3: publisher memicu event, handler dieksekusi
Tahap 4: subscriber melepas diri lewat -=
Pembayaran TRX-502 diprosesBedah Kode Baris per Baris #
Mari kita telaah kode di atas:
- Baris 3: Deklarasi event menandai tahap pertama. Sebelum ada
+=, pemanggilanInvokeakan melewati?.tanpa efek apa pun. - Baris 11-12: Local function
CatatKuitansimendaftar sebagai handler; inilah tahap langganan. - Baris 16:
Bayar("TRX-501")mencetak status pembayaran, lalu handler menjalankan pencetakan kuitansi. Urutan output menunjukkan pemicuan terjadi di dalam methodBayar. - Baris 19-21: Operator
-=menyelesaikan tahap pelepasan. PemanggilanBayar("TRX-502")hanya mencetak baris pembayaran tanpa kuitansi, sebab daftar handler sudah kosong.
Output menegaskan dua hal: handler hanya berjalan setelah terdaftar, terlihat dari kuitansi TRX-501 yang tercetak di antara dua baris Tahap, dan pemicuan setelah pelepasan tidak menjangkau handler apa pun, terlihat dari TRX-502 tanpa kuitansi. Ilustrasi empat tahap pada alur kecil ini mudah dipindahkan ke skenario aplikasi nyata.