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 bahwa TEventArgs harus merupakan kelas yang berasal dari System.EventArgs.

Ini meningkatkan fleksibilitas untuk Anda, dan kompatibel dengan versi sebelumnya. Mari kita mulai dengan fleksibilitas. Implementasi untuk System.EventArgs menggunakan metode yang didefinisikan dalam System.Object, yaitu metode MemberwiseClone(), yang membuat salinan dangkal dari objek. Metode tersebut harus menggunakan refleksi untuk mengimplementasikan fungsionalitasnya untuk kelas apa pun yang berasal dari EventArgs. Fungsionalitas tersebut lebih mudah dibuat di kelas turunan tertentu. Itu secara efektif berarti bahwa menggunakan System.EventArgs adalah batasan yang membatasi desain Anda, sementara tidak memberikan manfaat tambahan. Bahkan, Anda dapat mengubah definisi FileFoundArgs dan SearchDirectoryArgs sehingga tidak berasal dari EventArgs. Program ini bekerja persis sama.

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 ekstra adalah memanggil konstruktor tanpa parameter sebelum memasukkan konstruktor yang menginisialisasi semua bidang. Tanpa tambahan ini, aturan C# akan menunjukkan bahwa properti sedang diakses sebelum ditetapkan.

Anda tidak boleh mengubah FileFoundArgs dari kelas (jenis referensi) menjadi struct (jenis nilai). Protokol untuk menangani pembatalan mengharuskan Anda meneruskan argumen peristiwa dengan referensi. Jika Anda 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 dilihat oleh objek pencarian file.

Selanjutnya, mari kita pertimbangkan bagaimana perubahan ini dapat kompatibel ke belakang. Penghapusan batasan tidak memengaruhi kode yang ada. Setiap jenis argumen peristiwa yang ada masih berasal dari System.EventArgs. Kompatibilitas ke belakang adalah salah satu alasan utama mengapa mereka terus menerus berasal dari System.EventArgs. Setiap pelanggan acara yang ada adalah pelanggan acara 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 merusak basis kode tersebut.

Peristiwa dengan subskriber Asinkron

Anda memiliki satu pola akhir untuk dipelajari: Cara menulis subskriptor acara dengan benar yang menggunakan kode asinkron. Tantangan ini dijelaskan dalam artikel tentang asinkron dan menunggu. Metode asinkron dapat memiliki tipe pengembalian void, tetapi penggunaannya tidak disarankan. Ketika kode pendengar acara Anda memanggil metode asinkron, Anda tidak memiliki pilihan selain membuat metode async void. Tanda tangan penanganan aktivitas memerlukannya.

Anda perlu mendamaikan panduan yang berlawanan ini. Entah bagaimana, Anda harus membuat metode async void yang aman. Dasar-dasar pola yang perlu Anda terapkan ditampilkan dalam kode berikut:

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 handler ditandai sebagai handler asinkron. Karena sedang ditetapkan ke tipe delegasi penanganan acara, itu memiliki jenis pengembalian void. Itu berarti Anda harus mengikuti pola yang ditunjukkan dalam handler, dan tidak mengizinkan pengecualian apa pun dikeluarkan dari konteks handler asinkron. Karena tidak mengembalikan tugas, tidak ada tugas yang dapat melaporkan kesalahan dengan memasukkan status rusak. Karena metodenya adalah asinkron, metode tidak dapat melemparkan pengecualian. (Metode panggilan melanjutkan eksekusi karena nilainya async.) Perilaku aktual pada waktu proses memang didefinisikan secara berbeda untuk lingkungan yang berbeda. Ini dapat menghentikan utas atau proses yang memiliki utas tersebut, atau menyebabkan proses berada dalam keadaan tidak pasti. Semua potensi hasil ini sangat tidak diinginkan.

Anda harus membungkus ekspresi await untuk async Task di blok coba milik Anda sendiri. Jika itu menyebabkan tugas yang salah, Anda dapat mencatat kesalahan. Jika ini adalah kesalahan dari mana aplikasi Anda tidak dapat pulih, Anda dapat keluar dari program dengan cepat dan anggun

Artikel ini menjelaskan pembaruan utama untuk pola peristiwa .NET. Anda mungkin melihat banyak contoh versi sebelumnya di perpustakaan tempat Anda bekerja. Namun, Anda juga harus memahami pola terbaru. Anda dapat melihat kode yang sudah selesai untuk sampel di Program.cs.

Artikel berikutnya dalam seri ini membantu Anda membedakan antara menggunakan delegates dan events dalam desain Anda. Konsepnya mirip, dan artikel itu membantu Anda membuat keputusan terbaik untuk program Anda.

Berikutnya