我完全意识到,我提出的建议不遵循.NET准则,因此,仅鉴于此原因,可能是一个糟糕的主意。但是,我想从两个可能的角度考虑这一点:
(1)我是否应考虑将其用于我自己的开发工作,这是100%用于内部目的。
(2)这是框架设计者可以考虑更改或更新的概念吗?
我正在考虑使用利用强类型的“发送者”的事件签名,而不是将其键入为“对象”,这是当前的.NET设计模式。也就是说,不是使用如下所示的标准事件签名:
class Publisher
{
public event EventHandler<PublisherEventArgs> SomeEvent;
}
我正在考虑使用利用强类型的“发件人”参数的事件签名,如下所示:
首先,定义一个“ StrongTypedEventHandler”:
[SerializableAttribute]
public delegate void StrongTypedEventHandler<TSender, TEventArgs>(
TSender sender,
TEventArgs e
)
where TEventArgs : EventArgs;
这与Action <TSender,TEventArgs>并没有什么不同,但是通过使用StrongTypedEventHandler
,我们强制TEventArgs源自System.EventArgs
。
接下来,作为示例,我们可以在发布类中使用StrongTypedEventHandler,如下所示:
class Publisher
{
public event StrongTypedEventHandler<Publisher, PublisherEventArgs> SomeEvent;
protected void OnSomeEvent()
{
if (SomeEvent != null)
{
SomeEvent(this, new PublisherEventArgs(...));
}
}
}
上述安排将使订户能够使用不需要强制转换的强类型事件处理程序:
class Subscriber
{
void SomeEventHandler(Publisher sender, PublisherEventArgs e)
{
if (sender.Name == "John Smith")
{
// ...
}
}
}
我完全意识到这与标准.NET事件处理模式不符;但是,请记住,如果需要,可逆性将使订户能够使用传统的事件处理签名:
class Subscriber
{
void SomeEventHandler(object sender, PublisherEventArgs e)
{
if (((Publisher)sender).Name == "John Smith")
{
// ...
}
}
}
也就是说,如果事件处理程序需要订阅来自不同(或未知)对象类型的事件,则该处理程序可以将“ sender”参数键入“ object”,以处理潜在的发送方对象的全部范围。
除了打破常规(我不敢掉以轻心,相信我),我无法想到任何不利之处。
这里可能存在一些CLS合规性问题。这确实可以在Visual Basic .NET 2008中100%正常运行(我已经测试过),但是我认为直到2005年的Visual Basic .NET的较旧版本都没有委托协方差和相反方差。[编辑:我对此进行了测试,并确认:VB.NET 2005及以下版本无法处理此问题,但VB.NET 2008可以100%罚款。请参阅下面的“编辑#2”。]可能还有其他.NET语言对此也有问题,我不确定。
但是我看不到自己为C#或Visual Basic .NET以外的任何其他语言开发,也不介意将其限制为.NET Framework 3.0及更高版本的C#和VB.NET。(老实说,我无法想象现在回到2.0。)
有人能想到这个问题吗?还是这仅仅是与惯例大相径庭,以至于让人胃口大开?
这是我找到的一些相关链接:
(2)C#简单事件引发-使用“发送者”与自定义EventArgs [StackOverflow 2009]
(3).net中的事件签名模式[StackOverflow 2008]
我对任何人和每个人的看法都感兴趣...
提前致谢,
麦克风
编辑1:这是对Tommy Carlier的帖子的回应:
这是一个完整的工作示例,该示例显示强类型事件处理程序和使用“对象发送者”参数的当前标准事件处理程序都可以与该方法共存。您可以复制粘贴代码并运行它:
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();
}
}
}
编辑2:这是对安德鲁·黑尔(Andrew Hare)关于协方差和反方差及其在此处如何应用的陈述的回应。C#语言的代表之间一直有协变和矛盾,以至于感觉只是“内在的”,而事实并非如此。我不知道,它甚至可能是在CLR中启用的,但是直到.NET Framework 3.0(VB.NET 2008)为止,Visual Basic .NET才没有为其委托提供协方差和逆方差功能。因此,Visual Basic.NET for .NET 2.0及以下版本将无法使用此方法。
例如,可以将以上示例转换为VB.NET,如下所示:
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可以100%正常运行。但是为了确定起见,我现在已经在VB.NET 2005上对其进行了测试,并且没有编译,并指出:
方法“公共Sub SomeEventHandler(作为对象发送,作为vbGenericEventHandling.GenericEventHandling.PublisherEventArgs)”与委托“ Delegate Sub StrongTypedEventHandler(Of TSender,TEventArgs作为System.EventArgs)(作为发布者,作为PublisherEventArgs)不具有相同的签名。 '
基本上,委托在VB.NET 2005版及更低版本中是不变的。我实际上是在几年前想到这个主意的,但是VB.NET无法处理此问题令我感到困扰……但是我现在已经坚定地转向C#,并且VB.NET现在可以处理它了,所以,所以这个帖子。
编辑:更新#3
好的,我已经成功使用了一段时间了。这确实是一个不错的系统。我决定将“ StrongTypedEventHandler”命名为“ GenericEventHandler”,定义如下:
[SerializableAttribute]
public delegate void GenericEventHandler<TSender, TEventArgs>(
TSender sender,
TEventArgs e
)
where TEventArgs : EventArgs;
除了重命名之外,我完全按照上面的讨论实施了它。
它确实跳过了FxCop规则CA1009,该规则指出:
“按照惯例,.NET事件具有两个用于指定事件发送者和事件数据的参数。事件处理程序签名应遵循以下格式:void MyEventHandler(object sender,EventArgs e)。“ sender”参数始终为System.Object类型,即使可能使用更特定的类型,“ e”参数始终为System.EventArgs类型。不提供事件数据的事件应使用System.EventHandler委托类型。事件处理程序返回void,以便它们可以发送每个事件传递给多个目标方法。目标返回的任何值在第一次调用后都会丢失。”
当然,我们知道所有这些,并且无论如何都在违反规则。(在任何情况下,如果需要的话,所有事件处理程序都可以在其签名中使用标准的“对象发件人”,这是不间断的更改。)
因此,使用a SuppressMessageAttribute
可以解决问题:
[SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly",
Justification = "Using strong-typed GenericEventHandler<TSender, TEventArgs> event handler pattern.")]
我希望这种方法将来会成为标准。它确实非常好用。
感谢您的所有意见,我真的很感激...
麦克风
oh hi this my hom work solve it plz :code dump:
问题,而是我们从中学到的问题。
EventHandler<,>
起个名字GenericEventHandler<,>
。EventHandler<>
BCL中已经有一个泛型,仅被命名为EventHandler。因此EventHandler是一个更通用的名称,并且委托支持类型重载