Saya sepenuhnya menyadari bahwa apa yang saya usulkan tidak mengikuti pedoman NET, dan, oleh karena itu, mungkin ide yang buruk karena alasan ini saja. Namun, saya ingin mempertimbangkan ini dari dua kemungkinan perspektif:
(1) Haruskah saya mempertimbangkan untuk menggunakan ini untuk pekerjaan pengembangan saya sendiri, yang 100% untuk tujuan internal.
(2) Apakah ini konsep yang dapat dipertimbangkan oleh perancang kerangka kerja untuk diubah atau diperbarui?
Saya berpikir tentang menggunakan tanda tangan acara yang menggunakan 'pengirim' yang diketik kuat, alih-alih mengetiknya sebagai 'objek', yang merupakan pola desain .NET saat ini. Artinya, alih-alih menggunakan tanda tangan acara standar yang terlihat seperti ini:
class Publisher
{
public event EventHandler<PublisherEventArgs> SomeEvent;
}
Saya sedang mempertimbangkan untuk menggunakan tanda tangan acara yang menggunakan parameter 'pengirim' yang diketik kuat, sebagai berikut:
Pertama, tentukan "StrongTypedEventHandler":
[SerializableAttribute]
public delegate void StrongTypedEventHandler<TSender, TEventArgs>(
TSender sender,
TEventArgs e
)
where TEventArgs : EventArgs;
Ini tidak jauh berbeda dari Action <TSender, TEventArgs>, tetapi dengan menggunakan StrongTypedEventHandler
, kami memaksakan asal TEventArgs System.EventArgs
.
Selanjutnya, sebagai contoh, kita dapat menggunakan StrongTypedEventHandler di kelas penerbitan sebagai berikut:
class Publisher
{
public event StrongTypedEventHandler<Publisher, PublisherEventArgs> SomeEvent;
protected void OnSomeEvent()
{
if (SomeEvent != null)
{
SomeEvent(this, new PublisherEventArgs(...));
}
}
}
Pengaturan di atas akan memungkinkan pelanggan untuk menggunakan pengendali kejadian yang diketik kuat yang tidak memerlukan transmisi:
class Subscriber
{
void SomeEventHandler(Publisher sender, PublisherEventArgs e)
{
if (sender.Name == "John Smith")
{
// ...
}
}
}
Saya sepenuhnya menyadari bahwa ini melanggar pola penanganan peristiwa standar .NET; Namun, perlu diingat bahwa kontradiksi akan memungkinkan pelanggan untuk menggunakan tanda tangan penanganan acara tradisional jika diinginkan:
class Subscriber
{
void SomeEventHandler(object sender, PublisherEventArgs e)
{
if (((Publisher)sender).Name == "John Smith")
{
// ...
}
}
}
Artinya, jika penangan peristiwa perlu berlangganan peristiwa dari jenis objek yang berbeda (atau mungkin tidak diketahui), penangan dapat mengetikkan parameter 'pengirim' sebagai 'objek' untuk menangani keseluruhan objek pengirim potensial.
Selain melanggar konvensi (yang merupakan sesuatu yang tidak saya anggap enteng, percayalah) saya tidak dapat memikirkan kerugian apapun dari hal ini.
Mungkin ada beberapa masalah kepatuhan CLS di sini. Ini berjalan di Visual Basic .NET 2008 100% baik-baik saja (saya telah diuji), tetapi saya percaya bahwa versi Visual Basic .NET hingga 2005 tidak memiliki kovarian dan kontradiksi yang mendelegasikan. [Sunting: Saya telah menguji ini, dan sudah dikonfirmasi: VB.NET 2005 dan di bawahnya tidak dapat menangani ini, tetapi VB.NET 2008 100% baik-baik saja. Lihat "Edit # 2", di bawah.] Mungkin ada bahasa .NET lain yang juga bermasalah dengan ini, saya tidak yakin.
Tetapi saya tidak melihat diri saya mengembangkan bahasa apa pun selain C # atau Visual Basic .NET, dan saya tidak keberatan membatasinya ke C # dan VB.NET untuk .NET Framework 3.0 dan yang lebih baru. (Saya tidak bisa membayangkan kembali ke 2.0 pada saat ini, jujur.)
Adakah yang bisa memikirkan masalah dengan ini? Atau apakah ini hanya melanggar konvensi begitu banyak sehingga membuat perut orang mual?
Berikut beberapa tautan terkait yang saya temukan:
(1) Panduan Desain Acara [MSDN 3.5]
(2) C # Event Raising sederhana - menggunakan "sender" vs. EventArgs kustom [StackOverflow 2009]
(3) Pola tanda tangan acara di .net [StackOverflow 2008]
Saya tertarik dengan pendapat siapa pun dan semua orang tentang ini ...
Terima kasih sebelumnya,
Mike
Sunting # 1: Ini menanggapi posting Tommy Carlier :
Berikut adalah contoh kerja lengkap yang menunjukkan bahwa penangan kejadian yang diketik kuat dan penangan kejadian standar saat ini yang menggunakan parameter 'pengirim objek' dapat hidup berdampingan dengan pendekatan ini. Anda dapat menyalin-tempel kode dan menjalankannya:
namespace csScrap.GenericEventHandling
{
class PublisherEventArgs : EventArgs
{
// ...
}
[SerializableAttribute]
public delegate void StrongTypedEventHandler<TSender, TEventArgs>(
TSender sender,
TEventArgs e
)
where TEventArgs : EventArgs;
class Publisher
{
public event StrongTypedEventHandler<Publisher, PublisherEventArgs> SomeEvent;
public void OnSomeEvent()
{
if (SomeEvent != null)
{
SomeEvent(this, new PublisherEventArgs());
}
}
}
class StrongTypedSubscriber
{
public void SomeEventHandler(Publisher sender, PublisherEventArgs e)
{
MessageBox.Show("StrongTypedSubscriber.SomeEventHandler called.");
}
}
class TraditionalSubscriber
{
public void SomeEventHandler(object sender, PublisherEventArgs e)
{
MessageBox.Show("TraditionalSubscriber.SomeEventHandler called.");
}
}
class Tester
{
public static void Main()
{
Publisher publisher = new Publisher();
StrongTypedSubscriber strongTypedSubscriber = new StrongTypedSubscriber();
TraditionalSubscriber traditionalSubscriber = new TraditionalSubscriber();
publisher.SomeEvent += strongTypedSubscriber.SomeEventHandler;
publisher.SomeEvent += traditionalSubscriber.SomeEventHandler;
publisher.OnSomeEvent();
}
}
}
Sunting # 2: Ini adalah tanggapan atas pernyataan Andrew Hare tentang kovariansi dan kontradiksi dan bagaimana penerapannya di sini. Delegasi dalam bahasa C # telah lama mengalami kovarian dan kontradiksi sehingga hanya terasa "intrinsik", tetapi sebenarnya tidak. Bahkan mungkin sesuatu yang diaktifkan di CLR, saya tidak tahu, tetapi Visual Basic .NET tidak mendapatkan kemampuan kovarian dan kontradiksi untuk delegasinya hingga .NET Framework 3.0 (VB.NET 2008). Dan sebagai hasilnya, Visual Basic.NET untuk .NET 2.0 dan di bawahnya tidak dapat menggunakan pendekatan ini.
Misalnya contoh di atas dapat diterjemahkan ke dalam VB.NET sebagai berikut:
Namespace GenericEventHandling
Class PublisherEventArgs
Inherits EventArgs
' ...
' ...
End Class
<SerializableAttribute()> _
Public Delegate Sub StrongTypedEventHandler(Of TSender, TEventArgs As EventArgs) _
(ByVal sender As TSender, ByVal e As TEventArgs)
Class Publisher
Public Event SomeEvent As StrongTypedEventHandler(Of Publisher, PublisherEventArgs)
Public Sub OnSomeEvent()
RaiseEvent SomeEvent(Me, New PublisherEventArgs)
End Sub
End Class
Class StrongTypedSubscriber
Public Sub SomeEventHandler(ByVal sender As Publisher, ByVal e As PublisherEventArgs)
MessageBox.Show("StrongTypedSubscriber.SomeEventHandler called.")
End Sub
End Class
Class TraditionalSubscriber
Public Sub SomeEventHandler(ByVal sender As Object, ByVal e As PublisherEventArgs)
MessageBox.Show("TraditionalSubscriber.SomeEventHandler called.")
End Sub
End Class
Class Tester
Public Shared Sub Main()
Dim publisher As Publisher = New Publisher
Dim strongTypedSubscriber As StrongTypedSubscriber = New StrongTypedSubscriber
Dim traditionalSubscriber As TraditionalSubscriber = New TraditionalSubscriber
AddHandler publisher.SomeEvent, AddressOf strongTypedSubscriber.SomeEventHandler
AddHandler publisher.SomeEvent, AddressOf traditionalSubscriber.SomeEventHandler
publisher.OnSomeEvent()
End Sub
End Class
End Namespace
VB.NET 2008 dapat menjalankannya 100% dengan baik. Tapi sekarang saya sudah mengujinya di VB.NET 2005, hanya untuk memastikan, dan itu tidak bisa dikompilasi, menyatakan:
Metode 'Public Sub SomeEventHandler (sender As Object, e As vbGenericEventHandling.GenericEventHandling.PublisherEventArgs)' tidak memiliki tanda tangan yang sama dengan delegasi 'Delegate Sub StrongTypedEventHandler (Of TSender, TEventArgs As System.EventArgs) (sender As PublisherEvent, e Asrgs) '
Pada dasarnya, delegasi tidak berubah di VB.NET versi 2005 dan di bawahnya. Saya benar-benar memikirkan ide ini beberapa tahun yang lalu, tetapi ketidakmampuan VB.NET untuk menangani ini mengganggu saya ... Tapi sekarang saya telah pindah dengan kokoh ke C #, dan VB.NET sekarang dapat mengatasinya, jadi, yah, karenanya posting ini.
Edit: Perbarui # 3
Oke, saya telah menggunakan ini dengan cukup berhasil untuk beberapa waktu sekarang. Ini benar-benar sistem yang bagus. Saya memutuskan untuk menamai "StrongTypedEventHandler" saya sebagai "GenericEventHandler", yang didefinisikan sebagai berikut:
[SerializableAttribute]
public delegate void GenericEventHandler<TSender, TEventArgs>(
TSender sender,
TEventArgs e
)
where TEventArgs : EventArgs;
Selain penggantian nama ini, saya menerapkannya persis seperti yang dibahas di atas.
Itu tersandung aturan FxCop CA1009, yang menyatakan:
"Menurut konvensi, peristiwa .NET memiliki dua parameter yang menentukan pengirim peristiwa dan data peristiwa. Tanda tangan pengendali peristiwa harus mengikuti formulir ini: void MyEventHandler (pengirim objek, EventArgs e). Parameter 'pengirim' selalu berjenis System.Object, bahkan jika dimungkinkan untuk menggunakan jenis yang lebih spesifik. Parameter 'e' selalu berjenis System.EventArgs. Peristiwa yang tidak menyediakan data peristiwa harus menggunakan jenis delegasi System.EventHandler. Penangan peristiwa mengembalikan void sehingga mereka dapat mengirim setiap peristiwa ke beberapa metode target. Nilai apa pun yang dikembalikan oleh target akan hilang setelah panggilan pertama. "
Tentu saja, kami mengetahui semua ini, dan bagaimanapun juga kami melanggar aturan. (Semua penangan acara dapat menggunakan 'Pengirim objek' standar dalam tanda tangannya jika diinginkan dalam hal apa pun - ini adalah perubahan yang tidak dapat dipecahkan.)
Jadi penggunaan a berhasil SuppressMessageAttribute
:
[SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly",
Justification = "Using strong-typed GenericEventHandler<TSender, TEventArgs> event handler pattern.")]
Saya berharap pendekatan ini menjadi standar di beberapa titik di masa mendatang. Ini benar-benar bekerja dengan sangat baik.
Terima kasih untuk semua pendapat kalian, saya sangat menghargainya ...
Mike
oh hi this my hom work solve it plz :code dump:
pertanyaan berukuran tweet ini , tetapi pertanyaan yang kami pelajari .
EventHandler<,>
dari GenericEventHandler<,>
. Sudah ada generik EventHandler<>
di BCL yang dinamai hanya EventHandler. Jadi EventHandler adalah nama yang lebih umum dan delegasi mendukung kelebihan tipe