Bagikan melalui


Pola Peristiwa .NET Core yang Diperbarui

Sebelumnya

Artikel sebelumnya membahas pola peristiwa yang paling umum. .NET Core memiliki pola yang lebih santai. Dalam versi ini, definisi EventHandler<TEventArgs> tidak lagi memiliki batasan yang mengharuskan TEventArgs merupakan kelas turunan dari System.EventArgs.

Ini meningkatkan fleksibilitas untuk Anda, dan memiliki kompatibilitas mundur. Mari kita mulai dengan fleksibilitas. Kelas System.EventArgs memperkenalkan satu metode: MemberwiseClone(), yang membuat salinan objek dangkal. Metode tersebut harus menggunakan refleksi agar menerapkan fungsionalitasnya untuk kelas apa pun yang berasal dari EventArgs. Fungsionalitas tersebut lebih mudah dibuat di kelas turunan tertentu. Itu secara efektif berarti bahwa turunan dari System.EventArgs merupakan batasan yang membatasi desain Anda, tetapi tidak memberikan manfaat tambahan. Bahkan, Anda dapat mengubah definisi FileFoundArgs dan SearchDirectoryArgs sehingga keduanya tidak berasal dari EventArgs. Program tersebut akan bekerja dengan cara yang sama persis.

Anda juga dapat mengubah SearchDirectoryArgs menjadi struct, jika Anda membuat satu perubahan lagi:

internal struct SearchDirectoryArgs
{
    internal string CurrentSearchDirectory { get; }
    internal int TotalDirs { get; }
    internal int CompletedDirs { get; }

    internal SearchDirectoryArgs(string dir, int totalDirs, int completedDirs) : this()
    {
        CurrentSearchDirectory = dir;
        TotalDirs = totalDirs;
        CompletedDirs = completedDirs;
    }
}

Perubahan tambahan adalah untuk memanggil konstruktor tanpa parameter sebelum memasukkan konstruktor yang melakukan inisialisasi terhadap semua bidang. Tanpa tambahan tersebut, aturan C# akan melaporkan bahwa properti sedang diakses sebelum ditetapkan.

Anda tidak boleh mengubah FileFoundArgs dari kelas (jenis referensi) menjadi struct (jenis nilai). Hal itu karena protokol untuk menangani pembatalan mengharuskan argumen peristiwa diteruskan berdasarkan referensi. Jika Anda telah membuat perubahan yang sama, kelas pencarian file tidak pernah dapat mengamati perubahan apa pun yang dibuat oleh salah satu pelanggan peristiwa. Salinan baru struktur akan digunakan untuk setiap pelanggan, dan salinan tersebut akan menjadi salinan yang berbeda dari yang terlihat oleh objek pencarian file.

Selanjutnya, mari kita pertimbangkan bagaimana perubahan ini dapat kompatibel dengan versi sebelumnya. Penghapusan batasan tidak memengaruhi kode yang ada. Setiap jenis argumen peristiwa yang ada masih berasal dari System.EventArgs. Kompatibilitas mundur adalah salah satu alasan utama mengapa argumen peristiwa akan terus berasal dari System.EventArgs. Setiap pelanggan peristiwa yang ada akan menjadi pelanggan peristiwa yang mengikuti pola klasik.

Mengikuti logika serupa, jenis argumen peristiwa apa pun yang dibuat sekarang tidak akan memiliki pelanggan apa pun di basis kode yang ada. Jenis peristiwa baru yang tidak berasal dari System.EventArgs tidak akan merusak basis kode tersebut.

Peristiwa dengan pelanggan Asinkron

Anda memiliki satu pola akhir untuk dipelajari: Cara menulis pelanggan peristiwa dengan benar yang memanggil kode asinkron. Tantangan ini dijelaskan dalam artikel tentang async dan await. Metode asinkron dapat memiliki jenis pengembalian void, tetapi itu sangat tidak disarankan. Ketika kode pelanggan peristiwa Anda memanggil metode asinkron, Anda tidak memiliki pilihan selain membuat metode async void. Tanda tangan penanganan aktivitas memerlukannya.

Anda perlu merekonsiliasi panduan yang berlawanan ini. Entah kenapa, Anda harus membuat metode async void yang aman. Dasar-dasar pola yang perlu Anda terapkan di bawah ini:

worker.StartWorking += async (sender, eventArgs) =>
{
    try
    {
        await DoWorkAsync();
    }
    catch (Exception e)
    {
        //Some form of logging.
        Console.WriteLine($"Async task failure: {e.ToString()}");
        // Consider gracefully, and quickly exiting.
    }
};

Pertama, perhatikan bahwa penanganan ditandai sebagai penanganan asinkron. Karena sedang ditetapkan ke jenis delegasi penanganan aktivitas, penanganan aktivitas akan memiliki pengembalian void. Itu berarti Anda harus mengikuti pola yang ditunjukkan dalam penanganan, dan tidak mengizinkan pengecualian apa pun dilempar dari konteks penanganan asinkron. Karena tidak mengembalikan tugas, tidak ada tugas yang dapat melaporkan kesalahan dengan memasukkan status gagal. Karena metode ini merupakan asinkron, metode tidak bisa begitu saja melemparkan pengecualian. (Metode panggilan telah melanjutkan eksekusi karena itu adalah async.) Perilaku runtime bahasa umum aktual akan didefinisikan secara berbeda untuk lingkungan yang berbeda. Perilaku ini dapat mengakhiri utas atau proses yang memiliki utas, atau membiarkan proses dalam keadaan tidak ditentukan. Semua hasil potensial ini sangat tidak diharapkan.

Itu sebabnya Anda harus membungkus pernyataan await untuk Tugas asinkron di blok percobaan Anda sendiri. Jika itu menyebabkan tugas yang gagal, Anda dapat mencatat kesalahan. Jika ini adalah kesalahan yang menyebabkan aplikasi Anda tidak dapat pulih, Anda dapat keluar dari program dengan cepat dan anggun

Semua itu adalah pembaruan utama untuk pola peristiwa .NET. Anda akan melihat banyak contoh versi sebelumnya di pustaka yang Anda kerjakan. Namun, Anda juga harus memahami pola terbaru dengan sama baiknya.

Artikel berikutnya dalam seri ini membantu Anda membedakan antara penggunaan delegates dan events dalam desain Anda. Mereka adalah konsep yang sama, dan artikel tersebut akan membantu Anda membuat keputusan terbaik untuk program Anda.

Berikutnya