[ACCEPTED]-.NET EventHandlers - Generic or no?-events
Delegate of the following form has been 11 added since .NET Framework 2.0
public delegate void EventHandler<TArgs>(object sender, TArgs args) where TArgs : EventArgs
You approach 10 goes a bit further, since you provide out-of-the-box 9 implementation for EventArgs with single 8 data item, but it lacks several properties 7 of the original idea:
- 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.
So, I think it is better 6 to use generic EventHandler<T>, but 5 still have custom EventArgs classes, organized 4 according to the requirements of the data 3 model. With Visual Studio and extensions 2 like ReSharper, it is only a matter of few 1 commands to create new class like that.
To make generic event declaration easier, I 6 created a couple of code snippets for it. To 5 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:
Visual Studio 2008\Code Snippets\Visual C#\My Code Snippets
Here's one that uses a custom EventArgs 4 class with one property:
<?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 3 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 2 to create them with as many properties as 1 you like.
No, I don't think this is the wrong approach. I 2 think it's even recommended in the [fantastic] book 1 Framework Design Guidelines. I do the same thing.
This is the correct implementation. It has 4 been added to the .NET Framework (mscorlib) since 3 generics first came available (2.0).
For 2 more on its usage and implementation see 1 MSDN: http://msdn.microsoft.com/en-us/library/db0etb8x.aspx
The first time I saw this little pattern, I 4 was using Composite UI Application block, from MS Patterns & Practices 3 group.
It doesn't throw any red flag to me 2 ; in fact it is even a smart way of leveraging 1 generics to follow the DRY rule.
Since .NET 2.0
EventHandler<T>
has been implemented.
0
You can find Generic EventHandler on MSDN 9 http://msdn.microsoft.com/en-us/library/db0etb8x.aspx
I have been using generic EventHandler extensively 8 and was able to prevent so-called "Explosion 7 of Types(Classes)" Project was kept 6 smaller and easier to navigate around.
Coming 5 up with a new intuitive a delegate for non-generic 4 EventHandler delegate is painful and overlap 3 with existing types Appending "*EventHandler" to 2 new delegate name does not help much in 1 my opinion
I do believe that the recent versions of 9 .NET have just such an event handler defined 8 in them. That's a big thumbs up as far 7 as I'm concerned.
/EDIT
Didn't get the distinction 6 there originally. As long as you are passing 5 back a class that inherits from EventArgs, which 4 you are, I don't see a problem. I would 3 be concerned if you weren't wrapping the 2 resultfor maintainability reasons. I still 1 say it looks good to me.
Use generic event handler instances
Before 9 .NET Framework 2.0, in order to pass custom 8 information to the event handler, a new 7 delegate had to be declared that specified 6 a class derived from the System.EventArgs 5 class. This is no longer true in .NET
Framework 4 2.0, which introduced the System.EventHandler<T>) delegate. This 3 generic delegate allows any class derived 2 from EventArgs to be used with the event 1 handler.
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.