最佳实践:常见事件处理

3
在WinForms解决方案中,您有多个相同类型的控件。您需要为每个控件添加事件处理程序,并且当前时间事件处理程序将执行相同的操作。您不希望它们在未来有任何差异的原因。例如:
ScheduledPatientsGrid.ProcessGridKey += ScheduledPatientsGrid_ProcessGridKey;
RecentPatientsGrid.ProcessGridKey += RecentPatientsGrid_ProcessGridKey;
RecentPatientsGrid.ProcessGridKey += RecentPatientsGrid_ProcessGridKey;

... 

private void ScheduledPatientsGrid_ProcessGridKey(object sender, KeyEventArgs e)
{
   ...
}

private void RecentPatientsGrid_ProcessGridKey(object sender, KeyEventArgs e)
{
   ...
}

private void PatientsGrid_ProcessGridKey(object sender, KeyEventArgs e)
{
   ...
}

现在,是将单个事件处理程序共享于不同的事件之间,如下所示,还是像上面的代码示例中使用不同的事件处理程序更好?
ScheduledPatientsGrid.ProcessGridKey += ProcessGridKey;
RecentPatientsGrid.ProcessGridKey += ProcessGridKey;
RecentPatientsGrid.ProcessGridKey += ProcessGridKey;                


private void ProcessGridKey(object sender, KeyEventArgs e)
{
  ...
}

在下一页中,微软似乎暗示分享是更好的,但我注意到自.NET 2.0(即Visual Studio 2008)以来他们没有更新过它。

http://msdn.microsoft.com/en-us/library/4ac48519%28v=vs.90%29.aspx

这种情况下是否有一个指南可以提供最佳实践建议?
3个回答

10

我绝对会使用相同的方法。如果有多种做完全相同的事情但没有一个命名能表达它所做之意义,那还有什么好处呢?

个人很讨厌Visual Studio生成的命名方式。我更喜欢给我的事件处理器方法起有意义的名称来描述它们所实现的功能。这样当你在设计器中查看事件处理程序列表时,就可以看到当按钮被点击时,X将会发生而不是"按钮的单击事件处理程序将被调用"这种无用的描述。

或者,使用lambda表达式订阅事件并调用具有有意义参数的有意义方法。(sender和args经常是无用的事件处理程序参数。)


有道理。我从来没有考虑过设计师的方面(可能是因为我从来不使用设计师 >.>)。 - Chris Sinclair
@ChrisSinclair:如果您从未使用设计师,则更没有借口使用那些可怜的名称 ;) - Jon Skeet
也许吧。我倾向于将事件包装器解读为“当用户单击按钮”(或其他事件)时会发生什么,但仔细想想,我想事件侦听器确实不应该关心它们被调用的上下文。如果从鼠标单击更改为按键按下,那么我的代码的其余部分甚至需要关心吗?它应该关心吗?我想不应该。唯一重要的地方是在第一次注册事件的地方。谢谢,下次我连接事件时会认真考虑这个问题 :) - Chris Sinclair
4
再仔细考虑一下(庆幸的是,评论垃圾), 当注册监听器时,这甚至在很大程度上都很有意义。MyButton.Click += MyButton_Click 对我来说一点信息也没有,告诉我不了发生了什么。MyButton.Click += ValidateFormInput 告诉我按钮被点击时会执行验证操作;它更有用且易读。:D - Chris Sinclair

1
在这种情况下,我通常让他们包装一个常见的方法,但我会根据使用保留他们的事件处理程序名称。这使我能够轻松地对该方法进行单元测试,并(通常)减少所需的参数,任何堆栈跟踪中的错误都将非常易读,以确定哪个网格处理失败:
ScheduledPatientsGrid.ProcessGridKey += ScheduledPatientsGrid_ProcessGridKey;
RecentPatientsGrid.ProcessGridKey += RecentPatientsGrid_ProcessGridKey;
RecentPatientsGrid.ProcessGridKey += RecentPatientsGrid_ProcessGridKey;

... 

private void ScheduledPatientsGrid_ProcessGridKey(object sender, KeyEventArgs e)
{
   ProcessGridKey(e.Key);
}

private void RecentPatientsGrid_ProcessGridKey(object sender, KeyEventArgs e)
{
   ProcessGridKey(e.Key);
}

private void PatientsGrid_ProcessGridKey(object sender, KeyEventArgs e)
{
   ProcessGridKey(e.Key);
}

private void ProcessGridKey(Key e)
{
    ...
}

您的结果可能会因共享方法的操作或传入的参数而有所不同。(例如,在上面的示例中,我重复从KeyEventArgs中提取Key的操作。)


0

我更喜欢共享,如果逻辑变得混乱,你可以始终将单个事件用作路由器,指向正确的方法,例如...

private void ProcessGridKey(object sender, KeyEventArgs e)
{
     if (sender is x)
          xmethod();
     if (sender is y)
          ymethod();    //etc 
}

我知道这个语法在 OP 的例子中并不完全合理,因为发送者始终是相同的对象,但你可以理解这个概念。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接