Önerdiğim şeyin .NET yönergelerine uymadığının tamamen farkındayım ve bu nedenle, muhtemelen tek başına bu nedenle kötü bir fikirdir. Ancak, bunu iki olası bakış açısından değerlendirmek istiyorum:
(1) Bunu% 100 dahili amaçlar için kendi geliştirme çalışmam için kullanmayı düşünmeli miyim?
(2) Bu, çerçeve tasarımcılarının değiştirmeyi veya güncellemeyi düşünebilecekleri bir kavram mı?
Mevcut .NET tasarım modeli olan 'nesne' olarak yazmak yerine, güçlü yazılmış bir 'gönderici' kullanan bir olay imzası kullanmayı düşünüyorum. Yani, şuna benzeyen standart bir olay imzası kullanmak yerine:
class Publisher
{
public event EventHandler<PublisherEventArgs> SomeEvent;
}
Aşağıdaki gibi güçlü yazılmış bir "gönderen" parametresi kullanan bir etkinlik imzası kullanmayı düşünüyorum:
Önce bir "StrongTypedEventHandler" tanımlayın:
[SerializableAttribute]
public delegate void StrongTypedEventHandler<TSender, TEventArgs>(
TSender sender,
TEventArgs e
)
where TEventArgs : EventArgs;
Bu, bir Action <TSender, TEventArgs> 'dan çok da farklı değildir, ancak bunu kullanarak StrongTypedEventHandler
, TEventArgs'ın türetilmesini zorunlu kılıyoruz System.EventArgs
.
Ardından, örnek olarak StrongTypedEventHandler'ı aşağıdaki gibi bir yayınlama sınıfında kullanabiliriz:
class Publisher
{
public event StrongTypedEventHandler<Publisher, PublisherEventArgs> SomeEvent;
protected void OnSomeEvent()
{
if (SomeEvent != null)
{
SomeEvent(this, new PublisherEventArgs(...));
}
}
}
Yukarıdaki düzenleme, abonelerin, döküm gerektirmeyen güçlü tipte bir olay işleyicisini kullanmasına olanak tanır:
class Subscriber
{
void SomeEventHandler(Publisher sender, PublisherEventArgs e)
{
if (sender.Name == "John Smith")
{
// ...
}
}
}
Bunun standart .NET olay işleme modelinden tamamen koptuğunun farkındayım; ancak, kontravaryansın bir abonenin istenirse geleneksel bir olay işleme imzasını kullanmasını sağlayacağını unutmayın:
class Subscriber
{
void SomeEventHandler(object sender, PublisherEventArgs e)
{
if (((Publisher)sender).Name == "John Smith")
{
// ...
}
}
}
Yani, bir olay işleyicisinin farklı (veya belki bilinmeyen) nesne türlerinden gelen olaylara abone olması gerekiyorsa, işleyici, potansiyel gönderici nesnelerinin tüm genişliğini işlemek için "gönderen" parametresini "nesne" olarak yazabilir.
Konvansiyonu bozmaktan başka (ki bu hafife almadığım bir şey, inanın bana) bunda herhangi bir olumsuzluk düşünemiyorum.
Burada bazı CLS uyum sorunları olabilir. Bu, Visual Basic .NET 2008'de% 100 iyi çalışmaktadır (test ettim), ancak Visual Basic .NET'in 2005'e kadar olan eski sürümlerinde temsilci kovaryansı ve kontraveri olmadığına inanıyorum. [Düzenleme: O zamandan beri bunu test ettim ve onaylandı: VB.NET 2005 ve altı bunu kaldıramaz, ancak VB.NET 2008% 100 iyi. Aşağıdaki "Düzenleme # 2" ye bakın.] Bununla ilgili bir sorunu olan başka .NET dilleri de olabilir, emin olamıyorum.
Ancak kendimi C # veya Visual Basic .NET dışında herhangi bir dil için geliştirdiğimi görmüyorum ve bunu .NET Framework 3.0 ve üzeri için C # ve VB.NET ile sınırlandırmaktan çekinmiyorum. (Dürüst olmak gerekirse, bu noktada 2.0'a geri dönmeyi hayal bile edemezdim.)
Başka biri bununla ilgili bir sorun düşünebilir mi? Yoksa bu basitçe gelenekleri o kadar çok bozuyor ki insanların midesini döndürüyor mu?
İşte bulduğum bazı ilgili bağlantılar:
(1) Etkinlik Tasarım Yönergeleri [MSDN 3.5]
(2) C # basit Event Raising - "gönderen" ve özel EventArgs kullanarak [StackOverflow 2009]
(3) .net'te olay imza kalıbı [StackOverflow 2008]
Herkesin ve herkesin bu konudaki fikirleriyle ilgileniyorum ...
Şimdiden teşekkürler,
Mike
Düzenleme # 1: Bu, Tommy Carlier'ın gönderisine yanıt olarak :
Burada, hem kesin tipli olay işleyicilerin hem de 'nesne gönderen' parametresi kullanan geçerli standart olay işleyicilerin bu yaklaşımla bir arada var olabileceğini gösteren eksiksiz bir çalışma örneği verilmiştir. Kodu kopyalayıp yapıştırabilir ve çalıştırabilirsiniz:
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();
}
}
}
Düzenleme # 2: Bu, Andrew Hare'nin kovaryans ve kontravans ve burada nasıl geçerli olduğuna ilişkin açıklamasına bir yanıttır . C # dilindeki delegeler, o kadar uzun süredir kovaryans ve kontravere sahipler ki, bu sadece "içsel" hissediyor, ama değil. CLR'de etkinleştirilmiş bir şey bile olabilir, bilmiyorum, ancak Visual Basic .NET, .NET Framework 3.0'a (VB.NET 2008) kadar temsilciler için kovaryans ve kontravans kabiliyeti elde edemedi. Ve sonuç olarak, .NET 2.0 için Visual Basic.NET ve aşağısı bu yaklaşımı kullanamayacaktır.
Örneğin, yukarıdaki örnek aşağıdaki gibi VB.NET'e çevrilebilir:
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 onu% 100 iyi çalıştırabilir. Ama şimdi emin olmak için VB.NET 2005'te test ettim ve derlemiyor, şunu belirtiyor:
Yöntem 'Public Sub SomeEventHandler (gönderen Nesne, e vbGenericEventHandling.GenericEventHandling.PublisherEventArgs olarak)' temsilci ile aynı imzaya sahip değil 'Delege Sub StrongTypedEventHandler (TSender, TEventArgs As System.EventArgs) (Gönderen Yayımcı, e '
Temel olarak, temsilciler VB.NET'in 2005 ve daha önceki sürümlerinde değişmez. Aslında bu fikri birkaç yıl önce düşünmüştüm, ancak VB.NET'in bununla başa çıkamaması beni rahatsız etti ... Ama şimdi sağlam bir şekilde C #'a geçtim ve VB.NET artık bunu halledebilir, bu yüzden, iyi, bu yüzden bu gönderi.
Düzenleme: 3 numaralı güncelleme
Tamam, bir süredir bunu oldukça başarılı bir şekilde kullanıyorum. Gerçekten güzel bir sistem. "StrongTypedEventHandler" cihazımı aşağıdaki gibi "GenericEventHandler" olarak adlandırmaya karar verdim:
[SerializableAttribute]
public delegate void GenericEventHandler<TSender, TEventArgs>(
TSender sender,
TEventArgs e
)
where TEventArgs : EventArgs;
Bu yeniden adlandırmanın dışında, tam olarak yukarıda tartışıldığı gibi uyguladım.
FxCop kuralı CA1009'a göre hareket eder ve şunları belirtir:
"Kural olarak, .NET olaylarının olay gönderenini ve olay verilerini belirten iki parametresi vardır. Olay işleyici imzaları şu biçimi izlemelidir: void MyEventHandler (nesne gönderen, EventArgs e)." Gönderen "parametresi her zaman System.Object tipindedir, daha spesifik bir tür kullanmak mümkün olsa bile. 'e' parametresi her zaman System.EventArgs tipindedir. Olay verileri sağlamayan olaylar System.EventHandler temsilci türünü kullanmalıdır. Olay işleyicileri, gönderebilmeleri için void döndürür her olay birden çok hedef yönteme. Bir hedef tarafından döndürülen herhangi bir değer ilk çağrıdan sonra kaybolur. "
Elbette tüm bunları biliyoruz ve yine de kuralları çiğniyoruz. (Herhangi bir durumda tercih edilirse, tüm olay işleyicileri imzalarında standart 'nesne Gönderen'i kullanabilir - bu, kesintisiz bir değişikliktir.)
Öyleyse, a kullanımı SuppressMessageAttribute
hile yapar:
[SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly",
Justification = "Using strong-typed GenericEventHandler<TSender, TEventArgs> event handler pattern.")]
Umarım bu yaklaşım gelecekte bir noktada standart haline gelir. Gerçekten çok güzel çalışıyor.
Tüm görüşleriniz için teşekkürler beyler, gerçekten minnettarım ...
Mike
oh hi this my hom work solve it plz :code dump:
sorulardan biri değil , öğrendiğimiz bir soru .
EventHandler<,>
daha GenericEventHandler<,>
. EventHandler<>
BCL'de yalnızca EventHandler adlı jenerik var . Yani EventHandler daha yaygın bir isimdir ve delegeler tip aşırı yüklemelerini destekler