题
每次我开始在深C#项目中,我结束了大量的事件,真的只是需要通过一个单一项目。我坚持 EventHandler
/EventArgs
实践中,但我喜欢什么要做的就是这样的:
public delegate void EventHandler<T>(object src, EventArgs<T> args);
public class EventArgs<T>: EventArgs {
private T item;
public EventArgs(T item) {
this.item = item;
}
public T Item {
get { return item; }
}
}
后来,我可以拥有我
public event EventHandler<Foo> FooChanged;
public event EventHandler<Bar> BarChanged;
然而,似乎标准的。净是创建一个新的委派, EventArgs
类为每种类型的事件。是不是有什么错了我的一般方法?
编辑:因为这个职位是,我只是重新创造的这一个新的项目,并想要确定它是好。实际上,我是重新建立它作为我公布。我发现那有一个通用的
EventHandler<TEventArgs>
, 所以你并不需要创建通用的委托人,但是你仍然需要一般 EventArgs<T>
类,因为 TEventArgs: EventArgs
.
另一个编辑:一个缺点(对我)的内在的解决方案是额外的详细程度:
public event EventHandler<EventArgs<Foo>> FooChanged;
与
public event EventHandler<Foo> FooChanged;
它可以是一个痛苦的客户登记对你的事件,因为该系统名称空间是进口的默认,因此他们不得不手动找出你的名字空间,甚至有一个奇特的工具,如Resharper...任何人有任何想法有关?
解决方案
自.NET Framework 2.0
以来,已添加以下表单的委托public delegate void EventHandler<TArgs>(object sender, TArgs args) where TArgs : EventArgs
您的方法更进一步,因为您为具有单个数据项的EventArgs提供了开箱即用的实现,但它缺少原始想法的几个属性:
- 您无法在不更改相关代码的情况下向事件数据添加更多属性。您必须更改委托签名以向事件订阅者提供更多数据。
- 您的数据对象是通用的,但它也是<!>“匿名<!>”;在阅读代码时,您必须解密<!> quot; Item <!> quot;使用财产。它应该根据它提供的数据命名。
- 当您具有底层(项目)类型的层次结构时,以这种方式使用泛型,您无法建立EventArgs的并行层次结构。例如。 EventArgs的LT <!>;碱基类型GT <!>;不是EventArgs <!> lt; DerivedType <!> gt;的基类型,即使BaseType是DerivedType的基础。 醇>
所以,我认为最好使用通用的EventHandler <!> lt; T <!> gt;,但仍然有自定义的EventArgs类,根据数据模型的要求进行组织。使用Visual Studio和ReSharper之类的扩展,创建新类只需要很少的命令。
其他提示
要使一般事件的《宣言》更加容易,我创造了一对夫妇的代码段。使用它们:
- 拷贝的整个段。
- 它贴在一个文本的文件(例如在记事本).
- 保存文件。片断扩展。
- 把。段文件在您的适当段的目录,例如:
Visual Studio2008年\代码段\视C#\,我的代码段
这是一个使用定制定引类与一种财产:
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>Generic event with one type/argument.</Title>
<Shortcut>ev1Generic</Shortcut>
<Description>Code snippet for event handler and On method</Description>
<Author>Kyralessa</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>type</ID>
<ToolTip>Type of the property in the EventArgs subclass.</ToolTip>
<Default>propertyType</Default>
</Literal>
<Literal>
<ID>argName</ID>
<ToolTip>Name of the argument in the EventArgs subclass constructor.</ToolTip>
<Default>propertyName</Default>
</Literal>
<Literal>
<ID>propertyName</ID>
<ToolTip>Name of the property in the EventArgs subclass.</ToolTip>
<Default>PropertyName</Default>
</Literal>
<Literal>
<ID>eventName</ID>
<ToolTip>Name of the event</ToolTip>
<Default>NameOfEvent</Default>
</Literal>
</Declarations>
<Code Language="CSharp"><![CDATA[public class $eventName$EventArgs : System.EventArgs
{
public $eventName$EventArgs($type$ $argName$)
{
this.$propertyName$ = $argName$;
}
public $type$ $propertyName$ { get; private set; }
}
public event EventHandler<$eventName$EventArgs> $eventName$;
protected virtual void On$eventName$($eventName$EventArgs e)
{
var handler = $eventName$;
if (handler != null)
handler(this, e);
}]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
这里是一个具有两个特性:
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>Generic event with two types/arguments.</Title>
<Shortcut>ev2Generic</Shortcut>
<Description>Code snippet for event handler and On method</Description>
<Author>Kyralessa</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>type1</ID>
<ToolTip>Type of the first property in the EventArgs subclass.</ToolTip>
<Default>propertyType1</Default>
</Literal>
<Literal>
<ID>arg1Name</ID>
<ToolTip>Name of the first argument in the EventArgs subclass constructor.</ToolTip>
<Default>property1Name</Default>
</Literal>
<Literal>
<ID>property1Name</ID>
<ToolTip>Name of the first property in the EventArgs subclass.</ToolTip>
<Default>Property1Name</Default>
</Literal>
<Literal>
<ID>type2</ID>
<ToolTip>Type of the second property in the EventArgs subclass.</ToolTip>
<Default>propertyType1</Default>
</Literal>
<Literal>
<ID>arg2Name</ID>
<ToolTip>Name of the second argument in the EventArgs subclass constructor.</ToolTip>
<Default>property1Name</Default>
</Literal>
<Literal>
<ID>property2Name</ID>
<ToolTip>Name of the second property in the EventArgs subclass.</ToolTip>
<Default>Property2Name</Default>
</Literal>
<Literal>
<ID>eventName</ID>
<ToolTip>Name of the event</ToolTip>
<Default>NameOfEvent</Default>
</Literal>
</Declarations>
<Code Language="CSharp">
<![CDATA[public class $eventName$EventArgs : System.EventArgs
{
public $eventName$EventArgs($type1$ $arg1Name$, $type2$ $arg2Name$)
{
this.$property1Name$ = $arg1Name$;
this.$property2Name$ = $arg2Name$;
}
public $type1$ $property1Name$ { get; private set; }
public $type2$ $property2Name$ { get; private set; }
}
public event EventHandler<$eventName$EventArgs> $eventName$;
protected virtual void On$eventName$($eventName$EventArgs e)
{
var handler = $eventName$;
if (handler != null)
handler(this, e);
}]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
你可以遵循的模式创建他们的许多属性,因为你喜欢。
不,我不认为这是错误的做法。我认为它甚至可以在[精彩]一书框架设计指南中推荐。我做同样的事情。
这是正确的实施。它已被添加到.NET Framework(mscorlib),因为泛型首次出现(2.0)。
有关其使用和实现的更多信息,请参阅MSDN: http:// msdn .microsoft.com / EN-US /库/ db0etb8x.aspx
我第一次看到这个小图案时,我正在使用 DRY 规则的明智方式。
自.NET 2.0以来
EventHandler<T>
已经实施。
您可以在MSDN上找到Generic EventHandler http://msdn.microsoft。 COM / EN-US /库/ db0etb8x.aspx
我一直在广泛使用通用的EventHandler,并且能够阻止所谓的<!>“爆炸类型(类)<!>”; 项目保持较小,更容易导航。
为非通用的EventHandler委托提供新的直观委托是痛苦的,并且与现有类型重叠 附加<!>; * EventHandler <!>;在我看来,对新代表名称没什么帮助
我确实认为.NET的最新版本中只有这样的事件处理程序。就我而言,这是一个大拇指。
/ EDIT
最初没有得到区别。只要你传回一个继承自EventArgs的类,你就不会发现问题。如果由于可维护性原因而没有包装结果,我会担心。我仍然说它看起来不错。
使用通用事件处理程序实例
在.NET Framework 2.0之前,为了将自定义信息传递给事件处理程序,必须声明一个新的委托,指定从System.EventArgs类派生的类。这在.NET中不再适用
Framework 2.0,它引入了System.EventHandler <!> lt; T <!> gt;)委托。此通用委托允许从EventArgs派生的任何类与事件处理程序一起使用。