EventHandler Design Practices - c#

I've read that one benefit to the MyEventHandler/MyEventArgs model is that it allows standard event handlers to handle a variety of events. It sounds good, but perhaps I'm understanding how this is supposed to work. I have the following code:
public delegate void DataArrivalEventHandler
(object sender, DataArrivalEventArgs e);
public class DataArrivalEventArgs : EventArgs
{
public DateTime Arrival { get; protected set; }
public DataArrivalEventArgs()
{
Arrival = DateTime.Now;
}
public DataArrivalEventArgs(DateTime arrival)
{
Arrival = arrival;
}
}
...
_pipeReader.DataArrival += new EventHandler(Pipe_DataArrival);
...
private void Pipe_DataArrival(object sender, EventArgs e)
{
...
}
The code throws an error when I'm trying to add the event handler, however, saying that it cannot implicity cast DataArrivalEventHandler to EventHandler. Changing DataArrivalEventHandler(Pipe_DataArrival) to EventHandler(Pipe_DataArrival) fixes the problem, so I feel like you should be able to add generic event handlers to more specific events (I understand why you can't do it the other way around.)
Is how I have it the best way to do it, or is there a better convention?

The way you've got it is right.
There's no conversion from a more specific delegate type to a more general one - but there is a conversion from a method group with a more specific set of parameters to a delegate type with a more general set of parameters. (It works the other way for return types.)
Now C# 4 changes this slightly, as there is a conversion from (say) Action<string> to Action<object> - but this only happens for generic delegates, in terms of their type parameters.

I think delegate contravariance (assigning EventHandler delegate to DataArrivalEventHandler) does not work in .NET 1.1. It is available since .NET 2.0
(Your code looks like .NET 1.1 code)

Naming
There are a naming convention for events. In your case the event should be named DataArrived. Read more here: http://msdn.microsoft.com/en-us/library/h0eyck3s(v=VS.71).aspx
Delegates
You got two delegates for events that should be used: EventHandler and EventHandler<T>
Multihtreading
If you are using multithreading, init your event in the following way.
public event EventHandler<MyEventArgs> = delegate {};
In this way you don't have to worry about multithreading issues.

Related

Why can't I just use EventHandler<int> instead of deriving from EventArgs

The documentation for EventHandler<TEventArgs> says:
The second parameter is a type derived from EventArgs and supplies
any fields or properties needed to hold the event data.
and it seems to be generally recommended throughout the .Net documentation.
However it turns out that I can do the following which works just fine:
public event EventHandler<int> Panned;
and invoke the event handler as:
int value = 10;
if (Panned != null)
{
Panned(this, value);
}
and on the observer side:
subject.Panned += (sender, e) =>
{
Console.WriteLine(e);
};
To me this seems better than littering the code with little classes that inherit from EventArgs or having a generic EventArgs as proposed by Does .NET have a built-in EventArgs<T>?
So why is it required that I inherit the EventHandler generic argument from EventArgs?
If all you need to do is pass an int to the handler then what you are doing is fine.
It used to be the case (before .NET 4.5) that the EventHandler type argument TEventArgs was constrained to inherit from EventArgs but not anymore:
public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);
The fact that MS dropped the constraint should tell you that they were being too strict and what you are doing is fine.
In the case that you need to pass a complex type to the handler then you might aswell inherit EventArgs for reasons of polymorphism. Also, the EventArgs.Empty member is useful.
This is just a convention. In fact, you don't even have to use the EventHandler<> generic delegate. You could have:
public event Action SomeEvent;
public void OnAction()
{
var a = this.SomeEvent;
if (a != null)
{
a();
}
}
Of course, the convention is there for a reason. As far as I know, every standard .NET event follows the pattern of using a void-returning delegate that takes an object parameter and a second parameter of EventArgs or a derived type. This makes it easy to use these events without having to refer to the documentation each time.
Silly, Silly, Silly!
Will this work?...
class Program
{
public static event Func<int> SomeEvent;
static void Main(string[] args)
{
SomeEvent += () => 7;
SomeEvent += () => 8;
var a = SomeEvent();
Console.WriteLine(a);
}
}
I tried it: it does! Of course, it's very odd to have an event where the delegate has a return value, because it's not obvious which handler's value will be returned to the caller if there are multiple attached handlers. In the above example, it turns out that 8 is written to the console.
Interesting but, I suspect, useless ;-)
Would You Ever Use This?
I don't think it would ever be sensible to have a non-void returning delegate type, as in my example. However, you might consider using a delegate whose parameters are value types (structs, not classes) for performance reasons. It might be possible to use events without incurring the garbage collection penalty of allocating EventArgs objects on the heap.

Convert delegate to System.Action

Introduction
In my WP8 C#/XAML project I'm using events to notify my view that some async process is done.
I have two types of delegates.
I'm creating events from those delegates and there are several of them notifying my view that some operations are completed or started (in order to show progressbar, navigate to another page, disable some controls et cetera).
In order to raise these events I want to create a private "notification method", which would raise those delegates.
The method i have in mind is in Code Sample below as fireUpEvent method.
Code Sample
ReturnState enum
public enum ReturnState : int
{
state1 = 0,
... //for the purpose of the presentation
state6 = 15
...
}
Definitions of events & methods
public delegate void LoadingStartedEventHandler();
public delegate void LoadingFinishedEventHandler(ReturnState state);
public event LoadingStartedEventHandler LoadingStarted;
public event LoadingFinishedEventHandler LoadingFinished;
private void fireUpEvent(Action<ReturnState> action, Returnstate parameter)
{
if(action != null)
{
action(parameter);
}
}
private void fireUpEvent(Action action)
{
if(action != null)
{
action();
}
}
Usage
fireUpEvent(LoadingFinished, ReturnState.state1);
Description
The problem is, that when I try to compile I get an error saying:
Argument1: Cannot convert from 'XXXX.YYYY.SomeClass.LoadingFinishedEventHandler' to 'System.Action<XXXX.YYYY.Returnstate>'
I've tried googling, but haven't found any usefull stuff.
Why isn't it convertible?
I'd like to Action<ReturnState> and Action in those methods instead of specific delegates, is it possible?
Should I use any other "type" like Action instead?
The only two I know from this "grooup" are Func & Action, are there others?
To answer this line:
Why isn't it convertible?
They're different delegate types, and there's no reference conversion between different delegate types (other than in generic delegate types using generic variance). You can create an Action from a LoadingStartedEventHandler like this:
LoadingStartedEventHandler handler = ...; // Whatever
Action action = new Action(handler);
... and you could do the same the other way round, and with your other delegate type and Action<T>. But there's really no need to do that.
I'd like to Action<ReturnState> and Action in those methods instead of specific delegates, is it possible?
Yes - just don't declare the events using those delegates, and indeed don't declare the delegates at all!
You can change this:
public delegate void LoadingStartedEventHandler();
public delegate void LoadingFinishedEventHandler(ReturnState state);
public event LoadingStartedEventHandler LoadingStarted;
public event LoadingFinishedEventHandler LoadingFinished;
To this:
public event Action LoadingStarted;
public event Action<ReturnState> LoadingFinished;
Note that this violates the .NET conventions on events, mind you. By convention, events are declared with a delegate where the first parameter is the "sender", of type object, and the second parameter is of a type derived from EventArgs (or EventArgs itself). Whether or not that's important to you is for you to decide. If you decide to follow the convention, you'd basically want to create a type deriving from EventArgs holding a ReturnState, and then replace the events with:
public event EventHandler LoadingStarted;
public event EventHandler<ReturnStateEventArgs> LoadingFinished;
And change your helper methods to:
private void RaiseEvent(EventHandler<TEventArgs> handler,
TEventArgs parameter)
{
if(handler != null)
{
handler(this, parameter);
}
}
private void RaiseEvent(EventHandler handler)
{
if(handler != null)
{
handler(this, EventArgs.Empty);
}
}
(I've modified the method names to follow .NET conventions and use the .NET terminology for events, which are "raised" rather than "fired up".)
Mr. Skeet always make good answers. Here I'm providing another solution of what you stated in the question.
For these two:
Why isn't it convertible?
I'd like to Action and Action in those methods instead of specific delegates, is it possible?
Mr. Skeet has already answered.
For these two:
Should I use any other "type" like Action instead?
The only two I know from this "grooup" are Func & Action, are there others?
Your fireUpEvent method probably should not accept an arbritary type of delegate as a brittle design. But it is possible to do.
The ultimate base type of all delegate type in C# is Delegate; a limitation of Delegate is that it cannot be a where constraint in generic types and methods.
To answer the question(regardless of the concerning of design), you can say:
private void fireUpEvent(
Delegate loadingEvent, ReturnState? parameter=null) {
if(null!=loadingEvent) {
foreach(var d in loadingEvent.GetInvocationList()) {
var args=null!=parameter?new object[] { parameter }:null;
d.Method.Invoke(d.Target, args);
}
}
}
instead of the original two methods in your question, where the Target is the object which owns the method, would be treated as this, null if it's a static method. args is the argument list passing to the method.
This is just a way that you can achieve it, and I'm pretty sure Mr. Skeet's answer is absolutely better.

Additional functionality Events provide over delegate

As I understand an Event is a way for a class to allow clients to give it delegates to methods that should be called when the event occurs. When the event occurs, the delegate(s) given to it by its clients are invoked.
But as demonstrated in following code above said functionality can also be achieved by delegate only i.e. without using delegate.
class Program
{
static void Main(string[] args)
{
ListWithChangedEvent lwce = new ListWithChangedEvent();
lwce.delegateVariable = DelegateTestMethod;
lwce.Add("test");
Console.ReadLine();
}
public static void DelegateTestMethod(object sender, object e)
{
}
}
public delegate void ChangedEventHandler(object sender, object e);
public class ListWithChangedEvent : System.Collections.ArrayList
{
public override int Add(object value)
{
int result = base.Add(value);
if (delegateVariable != null)
delegateVariable(this, "");
return result;
}
public ChangedEventHandler delegateVariable;
}
So, I was wondering what additional functionality does Events provide?
So, I was wondering what additional functionality does Events provide?
Events provide two distinctly different advantages over exposing a public delegate:
You're making the intent very clear. A delegate is typically exposed publically for a very different purpose than an "event" - by using an event, you're very clearly saying "this is something that will get raised at a specific point". Exposing a delegate typically has a different meaning - most often a delegate in a public API is a required input for that API - ie: something that is used directly by the method, not an optional notification mechanism triggered by the method.
Events, technically, are not necessarily just a delegate. An event actually has the option of allowing custom add and remove accessors, which allow you to manually determine what happens when a subscriber subscribes or unsubscribes from the event. For example, many implementations of ICommand.CanExecuteChanged actually don't include their own delegate at all - but silently route to the CommandManager's RequerySuggested event.
Your example allows for a single delegate to be called. The event is a collection of delegates, meaning you can += and -= your heart away (even during event invocation).
event is just the access approach to the handler.
it wont allow you to do myHandler=myFunc;
only using += ( from outer class)
it was made that if another dumb use your code - so he wont destroy your chain by using = so you allow him only += or -=

Does .NET have a built-in EventArgs<T>?

I am getting ready to create a generic EventArgs class for event args that carry a single argument:
public class EventArg<T> : EventArgs
{
// Property variable
private readonly T p_EventData;
// Constructor
public EventArg(T data)
{
p_EventData = data;
}
// Property for EventArgs argument
public T Data
{
get { return p_EventData; }
}
}
Before I do that, does C# have the same feature built in to the language? I seem to recall coming across something like that when C# 2.0 came out, but now I can't find it.
Or to put it another way, do I have to create my own generic EventArgs class, or does C# provide one? Thanks for your help.
No. You probably were thinking of EventHandler<T>, which allows you to define the delegate for any specific type of EventArgs.
I personally don't feel that EventArgs<T> is quite as good of a fit, though. The information used as a "payload" in the event args should be, in my opinion, a custom class to make its usage and expected properties very clear. Using a generic class will prevent you from being able to put meaningful names into place. (What does "Data" represent?)
I must say I don't understand all the 'purists' here.
i.e. if you already have a bag class defined - which has all the specifics, properties etc. - why the hack create one extra unnecessary class just to be able to follow the event/args mechanism, signature style?
thing is - not everything that is in .NET - or is 'missing from' for that matter - is 'good' - MS's been 'correcting' itself for years...
I'd say just go and create one - like I did - cause I needed it just like that - and saved me lot of time,
It does exist. At least, it does now.
You can find DataEventArgs<TData> in some different Microsoft assemblies/namespaces, for instance Microsoft.Practices.Prism.Events. However these are namespaces that you might not find natural to include in your project so you might just use your own implementation.
In case you choose not to use Prism, but still would like to try a generic EventArgs approach.
public class GenericEventArgs<T> : EventArgs
{
public T EventData { get; private set; }
public GenericEventArgs(T EventData)
{
this.EventData = EventData;
}
}
// Use the following sample code to declare ObjAdded event
public event EventHandler<GenericEventArgs<TargetObjType>> ObjAdded;
// Use the following sample code to raise ObjAdded event
private void OnObjAdded(TargetObjType TargetObj)
{
if (ObjAdded!= null)
{
ObjAdded.Invoke(this, new GenericEventArgs<TargetObjType>(TargetObj));
}
}
// And finnaly you can subscribe your ObjAdded event
SubscriberObj.ObjAdded += (object sender, GenericEventArgs<TargetObjType> e) =>
{
// Here you can explore your e.EventData properties
};
THERE IS NO BUILT-IN GENERIC ARGS.
If you follow Microsoft EventHandler pattern, then you implement your derived EventArgs like you suggested:
public class MyStringChangedEventArgs : EventArgs { public string OldValue { get; set; } }.
HOWEVER - if your team style guide accepts a simplification - your project can use a lightweight events, like this:
public event Action<object, string> MyStringChanged;
usage :
// How to rise
private void OnMyStringChanged(string e)
{
Action<object, string> handler = MyStringChanged; // thread safeness
if (handler != null)
{
handler(this, e);
}
}
// How to handle
myObject.MyStringChanged += (sender, e) => Console.WriteLine(e);
Usually a PoC projects use the latter approach. In professional applicatons, however, be aware of FX cop justification #CA1009: https://msdn.microsoft.com/en-us/library/ms182133.aspx
The problem with a generic type is that even if DerivedType inherits from BaseType, EventArgs(DerivedType) would not inherit from EventArgs(BaseType). Using EventArgs(BaseType) would thus prevent later using a derived version of the type.
The reason this does not exist is because what would end up happening is you implement this, and then when you go to fill in the T you should create a class with strongly typed unambiguous properties that acts as the data bag for your event arg, but halfway through implementing that you realize there's no reason you don't just make that class inherit from EventArgs and call it good.
Unless you just want a string or something similarly basic for your data bag, in which case there are probably EventArgs classes standard in .NET which are meant to serve whatever simple purpose you're getting at.

Custom Control Events in C#

I'm trying to create a custom control and need to raise an event from it. The idea is to raise an event at the end of the click event (OnAfterClick). I found one or two tutorials on doing this, but am clearly missing a step somewhere; I have the following.
In the control:
public class AfterClickEventArgs : EventArgs
{
...
}
public partial class MyButton : CommandButton
{
public delegate void AfterClickEvnt(object sender, AfterClickEventArgs e);
public event AfterClickUpdatedEvnt AfterClick;
}
protected override void OnClick(EventArgs e)
{
...
Processing here
...
AfterClickEventArgs myArgs = new AfterClickEventArgs();
AfterClick(this, myArgs);
}
In the program using the control:
In InitializeComponent():
this.MyButton.AfterClick += new System.EventHandler(this.cmdMyButton_Click);
This line is giving me a compile error (cmdMyButton_Click does exist). It tells me:
Cannot implicitly convert type 'System.EventHandler' to 'Namespace.MyButton.AfterClick'
Can anyone tell me what I'm missing, or misunderstanding about this, please?
Your event is declared to be of type AfterClickEvnt, but you're trying to subscribe to it using an EventHandler. You can't convert between the two.
Options:
Explicitly state the right type:
this.MyButton.AfterClick += new AfterClickEvnt(this.cmdMyButton_Click);
Use an implicit method group conversion:
this.MyButton.AfterClick += cmdMyButton_Click;
By the way, I suggest you remove your custom delegate type and instead use the generic EventHandler<T> delegate:
public event EventHandler<AfterClickEventArgs> AfterClick;
There is some discrepancies in your code, so it's hard to say what is going on. (myArgs became newArgs, and AfterClickUpdateEvnt became AfterClickEvnt). You also attempt to use an EventHandler in place of your delegate.
Also, it's better to use EventHandler<T> so that you don't have to bother with a delegate:
public event EventHandler<AfterClickEventArgs> AfterClick;

Categories

Resources