Event Action<> VS Event Eventhandler<>

event Action vs event EventHandler

The main difference will be that if you use Action<> your event will not follow the design pattern of virtually any other event in the system, which I would consider a drawback.

One upside with the dominating design pattern (apart from the power of sameness) is that you can extend the EventArgs object with new properties without altering the signature of the event. This would still be possible if you used Action<SomeClassWithProperties>, but I don't really see the point with not using the regular approach in that case.

Events, Delegates vs ActionsT

Action<T> is just an easy generic way to use delegates. It's equivalent to delegate MyDelegate(T arg)
It was added to save you some typing and it really saves the reader a LOT of hassle when trying to figure out what your delegate uses as parameters.

The event keyword has special meaning. It prevents this delegate from being triggered outside of the class. See this excellent answer for a discussion of why event is important and when you would use it (or not).

Difference between event Action and event EventHandlerEventArgs

When you use Action, you are not passing the Sender object to the event handler. Sometimes it is useful for the event handler to know what object triggered the event.

ActionT vs delegate event

Fwiw, neither example uses standard .NET conventions. The EventHandler<T> generic should declare the event:

public event EventHandler<EmployeeEventArgs> Leave;

The "On" prefix should be reserved for a protected method that raises the event:

protected virtual void OnLeave(EmployeeEventArgs e) {
var handler = Leave;
if (handler != null) handler(this, e);
}

You don't have to do it this way, but anybody will instantly recognize the pattern, understand your code and know how to use and customize it.

And it has the great advantage of not being forced to choose between a custom delegate declaration and Action<>, EventHandler<> is the best way. Which answers your question.

Action Vs event Action

It's not called an overload.

Basically, there is a set of types, declared like this:

namespace System {
delegate void Action();
delegate void Action<T>(T a);
delegate void Action<T1, T2>(T1 a1, T2 a2);
...
}

Each of them is a different type, independent of all other. The compiler knows which type you mean when you try to reference it by the presence or absence of <> after the type name, and the number of type parameters within <>.

event is a different thing altogether, and doesn't play any part in this. If you're confused by the difference between event and delegate, see these two questions: 1 2

Understanding events and event handlers in C#

To understand event handlers, you need to understand delegates. In C#, you can think of a delegate as a pointer (or a reference) to a method. This is useful because the pointer can be passed around as a value.

The central concept of a delegate is its signature, or shape. That is (1) the return type and (2) the input arguments. For example, if we create a delegate void MyDelegate(object sender, EventArgs e), it can only point to methods which return void, and take an object and EventArgs. Kind of like a square hole and a square peg. So we say these methods have the same signature, or shape, as the delegate.

So knowing how to create a reference to a method, let's think about the purpose of events: we want to cause some code to be executed when something happens elsewhere in the system - or "handle the event". To do this, we create specific methods for the code we want to be executed. The glue between the event and the methods to be executed are the delegates. The event must internally store a "list" of pointers to the methods to call when the event is raised.* Of course, to be able to call a method, we need to know what arguments to pass to it! We use the delegate as the "contract" between the event and all the specific methods that will be called.

So the default EventHandler (and many like it) represents a specific shape of method (again, void/object-EventArgs). When you declare an event, you are saying which shape of method (EventHandler) that event will invoke, by specifying a delegate:

//This delegate can be used to point to methods
//which return void and take a string.
public delegate void MyEventHandler(string foo);

//This event can cause any method which conforms
//to MyEventHandler to be called.
public event MyEventHandler SomethingHappened;

//Here is some code I want to be executed
//when SomethingHappened fires.
void HandleSomethingHappened(string foo)
{
//Do some stuff
}

//I am creating a delegate (pointer) to HandleSomethingHappened
//and adding it to SomethingHappened's list of "Event Handlers".
myObj.SomethingHappened += new MyEventHandler(HandleSomethingHappened);

//To raise the event within a method.
SomethingHappened("bar");

(*This is the key to events in .NET and peels away the "magic" - an event is really, under the covers, just a list of methods of the same "shape". The list is stored where the event lives. When the event is "raised", it's really just "go through this list of methods and call each one, using these values as the parameters". Assigning an event handler is just a prettier, easier way of adding your method to this list of methods to be called).

raising events using event ActionT

This way is much better, send bytesToUpload and totalToUpload through event, instead of the whole Action (right sample):

  internal class Program
{
private static void Main(string[] args)
{
SomeClass someClass = new SomeClass();
someClass.UploadProgress += SomeClass_UploadProgress;
someClass.DoSomeUpload();
}

private static void SomeClass_UploadProgress(object sender, UploadEventArgs e)
{
string s = string.Format("sending file data {0:0.000}%", (e.BytesSoFar * 100.0f) / e.TotalToUpload);
Console.WriteLine(s);
}
}

public class UploadEventArgs : EventArgs
{
public float BytesSoFar { get; set; }
public float TotalToUpload { get; set; }
}

public class SomeClass
{
public event EventHandler<UploadEventArgs> UploadProgress;

public void DoSomeUpload()
{
if (UploadProgress != null)
{
UploadEventArgs e = new UploadEventArgs();
e.BytesSoFar = 123f;
e.TotalToUpload = 100000f;
UploadProgress.Invoke(this, e);
}
}
}


Related Topics



Leave a reply



Submit