.NET EventHandlers – 通用还是不通用?

每次我深入开始一个C#项目时,我最终都会遇到许多事件,而这些事件实际上只需要传递一个项目。 我坚持使用EventHandler / EventArgs练习,但我喜欢做的是:

 public delegate void EventHandler(object src, EventArgs args); public class EventArgs: EventArgs { private T item; public EventArgs(T item) { this.item = item; } public T Item { get { return item; } } } 

后来,我可以拥有我的

 public event EventHandler FooChanged; public event EventHandler BarChanged; 

但是,似乎.NET的标准是为每种类型的事件创建一个新的委托和EventArgs子类。 我的通用方法有问题吗?


编辑:这篇文章的原因是我刚刚在一个新项目中重新创建了它,并希望确保它没问题。 实际上,我在发布时正在重新创建它。 我发现有一个通用的EventHandler ,所以你不需要创建generics委托,但是你仍然需要通用的EventArgs类,因为TEventArgs: EventArgs


另一个编辑:内置解决方案的一个缺点(对我而言)是额外的冗长:

 public event EventHandler<EventArgs> FooChanged; 

 public event EventHandler FooChanged; 

但是客户注册你的事件可能会很麻烦,因为系统名称空间是默认导入的,所以他们必须手动寻找你的命名空间,即使是像Resharper这样的花哨工具……任何人都有任何与之相关的想法?

自.NET Framework 2.0以来,已添加以下表单的委托

 public delegate void EventHandler(object sender, TArgs args) where TArgs : EventArgs 

您的方法更进一步,因为您为具有单个数据项的EventArgs提供了开箱即用的实现,但它缺少原始想法的几个属性:

  1. 您无法在不更改相关代码的情况下向事件数据添加更多属性。 您必须更改委托签名以向事件订阅者提供更多数据。
  2. 您的数据对象是通用的,但它也是“匿名的”,在阅读代码时,您必须从用法中解读“Item”属性。 它应该根据它提供的数据命名。
  3. 通过这种方式使用generics,当您具有底层(项)类型的层次结构时,您无法建立EventArgs的并行层次结构。 例如,EventArgs 不是EventArgs 的基本类型,即使BaseType是DerivedType的基础。

所以,我认为最好使用通用的EventHandler ,但仍然有自定义的EventArgs类,根据数据模型的要求进行组织。 使用Visual Studio和像ReSharper这样的扩展,只需要很少的命令来创建像这样的新类。

为了使通用事件声明更容易,我为它创建了几个代码片段。 要使用它们:

  • 复制整个代码段。
  • 将其粘贴到文本文件中(例如在记事本中)。
  • 使用.snippet扩展名保存文件。
  • 将.snippet文件放在相应的代码段目录中,例如:

Visual Studio 2008 \ Code Snippets \ Visual C#\ My Code Snippets

这是一个使用自定义EventArgs类和一个属性的类:

    
Generic event with one type/argument. ev1Generic Code snippet for event handler and On method Kyralessa Expansion
type Type of the property in the EventArgs subclass. propertyType argName Name of the argument in the EventArgs subclass constructor. propertyName propertyName Name of the property in the EventArgs subclass. PropertyName eventName Name of the event NameOfEvent $eventName$; protected virtual void On$eventName$($eventName$EventArgs e) { var handler = $eventName$; if (handler != null) handler(this, e); }]]>

这是一个有两个属性的:

    
Generic event with two types/arguments. ev2Generic Code snippet for event handler and On method Kyralessa Expansion
type1 Type of the first property in the EventArgs subclass. propertyType1 arg1Name Name of the first argument in the EventArgs subclass constructor. property1Name property1Name Name of the first property in the EventArgs subclass. Property1Name type2 Type of the second property in the EventArgs subclass. propertyType1 arg2Name Name of the second argument in the EventArgs subclass constructor. property1Name property2Name Name of the second property in the EventArgs subclass. Property2Name eventName Name of the event NameOfEvent $eventName$; protected virtual void On$eventName$($eventName$EventArgs e) { var handler = $eventName$; if (handler != null) handler(this, e); }]]>

您可以按照模式使用任意数量的属性创建它们。

不,我不认为这是错误的做法。 我认为它甚至在[精彩]书籍框架设计指南中被推荐 。 我做同样的事情。

这是正确的实现。 它已被添加到.NET Framework(mscorlib),因为generics首次出现(2.0)。

有关其使用和实现的更多信息,请参阅MSDN: http : //msdn.microsoft.com/en-us/library/db0etb8x.aspx

我第一次看到这个小模式,我正在使用来自MS Patterns&Practices组的Composite UI Application块 。

它不会给我任何红旗; 事实上,它甚至是一种利用generics来遵循DRY规则的聪明方法。

从.NET 2.0开始

EventHandler

已实施。

您可以在MSDN上找到Generic EventHandler http://msdn.microsoft.com/en-us/library/db0etb8x.aspx

我一直在广泛使用通用的EventHandler,并且能够阻止所谓的“类型(类)爆炸”项目保持更小,更容易导航。

提出一个新的直观的非通用EventHandler委托的委托是痛苦的,并与现有类型重叠将“* EventHandler”添加到新的委托名称对我来说没有多大帮助

我确实认为.NET的最新版本中只有这样的事件处理程序。 就我而言,这是一个大拇指。

/编辑

最初没有得到区别。 只要你传回一个inheritance自EventArgs的类,你就不会发现问题了。 如果由于可维护性原因而没有包装结果,我会担心。 我仍然说它对我来说很好看。

使用通用事件处理程序实例

在.NET Framework 2.0之前,为了将自定义信息传递给事件处理程序,必须声明一个新的委托,该委托指定从System.EventArgs类派生的类。 这在.NET中已不再适用

Framework 2.0,它引入了System.EventHandler )委托。 此通用委托允许从EventArgs派生的任何类与事件处理程序一起使用。