C# .NET EventHandlers - 通用还是不通用?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/129453/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
.NET EventHandlers - Generic or no?
提问by Chris Marasti-Georg
Every time I start in deep in a C# project, I end up with lots of events that really just need to pass a single item. I stick with the EventHandler
/EventArgs
practice, but what I like to do is have something like:
每次我开始深入研究 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; }
}
}
Later, I can have my
以后我可以有我的
public event EventHandler<Foo> FooChanged;
public event EventHandler<Bar> BarChanged;
However, it seems that the standard for .NET is to create a new delegate and EventArgs
subclass for each type of event. Is there something wrong with my generic approach?
然而,.NET 的标准似乎是EventArgs
为每种类型的事件创建一个新的委托和子类。我的通用方法有问题吗?
编辑:这篇文章的原因是我刚刚在一个新项目中重新创建了它,并想确保它没问题。实际上,我在发布时正在重新创建它。我发现有一个 generic
EventHandler<TEventArgs>
EventHandler<TEventArgs>
,所以你不需要创建泛型委托,但你仍然需要泛型EventArgs<T>
EventArgs<T>
类,因为TEventArgs: EventArgs
TEventArgs: EventArgs
.
另一个编辑:内置解决方案的一个缺点(对我来说)是额外的冗长:
public event EventHandler<EventArgs<Foo>> FooChanged;
vs.
对比
public event EventHandler<Foo> FooChanged;
It can be a pain for clients to register for your events though, because the System namespace is imported by default, so they have to manually seek out your namespace, even with a fancy tool like Resharper... Anyone have any ideas pertaining to that?
但是,客户端注册您的事件可能会很痛苦,因为默认情况下会导入 System 命名空间,因此即使使用 Resharper 这样的奇特工具,他们也必须手动查找您的命名空间...任何人对此都有任何想法?
采纳答案by Ilya Ryzhenkov
Delegate of the following form has been added since .NET Framework 2.0
自 .NET Framework 2.0 起添加了以下形式的委托
public delegate void EventHandler<TArgs>(object sender, TArgs args) where TArgs : EventArgs
You approach goes a bit further, since you provide out-of-the-box implementation for EventArgs with single data item, but it lacks several properties of the original idea:
您的方法更进一步,因为您为具有单个数据项的 EventArgs 提供了开箱即用的实现,但它缺少原始想法的几个属性:
- You cannot add more properties to the event data without changing dependent code. You will have to change the delegate signature to provide more data to the event subscriber.
- Your data object is generic, but it is also "anonymous", and while reading the code you will have to decipher the "Item" property from usages. It should be named according to the data it provides.
- Using generics this way you can't make parallel hierarchy of EventArgs, when you have hierarchy of underlying (item) types. E.g. EventArgs<BaseType> is not base type for EventArgs<DerivedType>, even if BaseType is base for DerivedType.
- 您不能在不更改相关代码的情况下向事件数据添加更多属性。您将不得不更改委托签名以向事件订阅者提供更多数据。
- 您的数据对象是通用的,但它也是“匿名的”,在阅读代码时,您必须从用法中破译“Item”属性。它应该根据它提供的数据命名。
- 当您具有底层(项目)类型的层次结构时,以这种方式使用泛型您无法创建 EventArgs 的并行层次结构。例如,EventArgs<BaseType> 不是 EventArgs<DerivedType> 的基类型,即使 BaseType 是 DerivedType 的基类型。
So, I think it is better to use generic EventHandler<T>, but still have custom EventArgs classes, organized according to the requirements of the data model. With Visual Studio and extensions like ReSharper, it is only a matter of few commands to create new class like that.
所以,我认为最好使用通用的 EventHandler<T>,但仍然有自定义的 EventArgs 类,根据数据模型的要求进行组织。使用 Visual Studio 和 ReSharper 等扩展,创建这样的新类只需几个命令。
回答by swilliams
No, I don't think this is the wrong approach. I think it's even recommended in the [fantastic] book Framework Design Guidelines. I do the same thing.
不,我不认为这是错误的方法。我认为它甚至在 [fantastic] 书Framework Design Guidelines 中得到了推荐。我做同样的事情。
回答by Chuck
I do believe that the recent versions of .NET have just such an event handler defined in them. That's a big thumbs up as far as I'm concerned.
我确实相信最近版本的 .NET 中定义了这样一个事件处理程序。就我而言,这是一个大大的赞许。
/EDIT
/编辑
Didn't get the distinction there originally. As long as you are passing back a class that inherits from EventArgs, which you are, I don't see a problem. I would be concerned if you weren't wrapping the resultfor maintainability reasons. I still say it looks good to me.
原来没有区别。只要您传回一个继承自 EventArgs 的类,您就是这样,我看不出有什么问题。如果您出于可维护性原因没有包装结果,我会担心。我仍然说它对我来说很好看。
回答by David Walschots
This is the correct implementation. It has been added to the .NET Framework (mscorlib) since generics first came available (2.0).
这是正确的实现。自从泛型首次可用 (2.0) 以来,它已被添加到 .NET Framework (mscorlib)。
For more on its usage and implementation see MSDN: http://msdn.microsoft.com/en-us/library/db0etb8x.aspx
有关其使用和实现的更多信息,请参阅 MSDN:http: //msdn.microsoft.com/en-us/library/db0etb8x.aspx
回答by mattlant
Since .NET 2.0
从 .NET 2.0 开始
EventHandler<T>
EventHandler<T>
has been implemented.
已实施。
回答by Romain Verdier
The first time I saw this little pattern, I was using Composite UI Application block, from MS Patterns & Practices group.
我第一次看到这个小模式时,我使用的是来自 MS Patterns & Practices 组的Composite UI Application block。
It doesn't throw any red flag to me ; in fact it is even a smart way of leveraging generics to follow the DRYrule.
它不会向我抛出任何危险信号;事实上,它甚至是利用泛型遵循DRY规则的一种聪明方式。
回答by dance2die
You can find Generic EventHandler on MSDN http://msdn.microsoft.com/en-us/library/db0etb8x.aspx
您可以在 MSDN http://msdn.microsoft.com/en-us/library/db0etb8x.aspx上找到 Generic EventHandler
I have been using generic EventHandler extensively and was able to prevent so-called "Explosion of Types(Classes)" Project was kept smaller and easier to navigate around.
我一直在广泛使用通用 EventHandler 并能够防止所谓的“类型(类)爆炸”项目保持较小且易于导航。
Coming up with a new intuitive a delegate for non-generic EventHandler delegate is painful and overlap with existing types Appending "*EventHandler" to new delegate name does not help much in my opinion
为非通用 EventHandler 委托提出一个新的直观的委托是痛苦的,并且与现有类型重叠在我看来,将“*EventHandler”附加到新的委托名称并没有多大帮助
回答by Ryan Lundy
To make generic event declaration easier, I created a couple of code snippets for it. To use them:
为了使通用事件声明更容易,我为它创建了几个代码片段。要使用它们:
- Copy the whole snippet.
- Paste it in a text file (e.g. in Notepad).
- Save the file with a .snippet extension.
- Put the .snippet file in your appropriate snippet directory, such as:
- 复制整个片段。
- 将其粘贴到文本文件中(例如在记事本中)。
- 使用 .snippet 扩展名保存文件。
- 将 .snippet 文件放在适当的代码段目录中,例如:
Visual Studio 2008\Code Snippets\Visual C#\My Code Snippets
Visual Studio 2008\Code Snippets\Visual C#\My Code Snippets
Here's one that uses a custom EventArgs class with one property:
这是一个使用具有一个属性的自定义 EventArgs 类的方法:
<?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>Ryan Lundy</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>
<Imports>
<Import>
<Namespace>System</Namespace>
</Import>
</Imports>
</Snippet>
</CodeSnippet>
</CodeSnippets>
And here's one that has two properties:
这是一个有两个属性的:
<?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>Ryan Lundy</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>
<Imports>
<Import>
<Namespace>System</Namespace>
</Import>
</Imports>
</Snippet>
</CodeSnippet>
</CodeSnippets>
You can follow the pattern to create them with as many properties as you like.
您可以按照该模式使用任意数量的属性创建它们。
回答by ligaoren
Use generic event handler instances
使用通用事件处理程序实例
Before .NET Framework 2.0, in order to pass custom information to the event handler, a new delegate had to be declared that specified a class derived from the System.EventArgs class. This is no longer true in .NET
在 .NET Framework 2.0 之前,为了将自定义信息传递给事件处理程序,必须声明一个新委托,指定从 System.EventArgs 类派生的类。这在 .NET 中不再适用
Framework 2.0, which introduced the System.EventHandler<T>) delegate. This generic delegate allows any class derived from EventArgs to be used with the event handler.
Framework 2.0,引入了 System.EventHandler<T>) 委托。此通用委托允许从 EventArgs 派生的任何类与事件处理程序一起使用。