EventHandler vs Action

Is there a difference between using the following? I have seen instructors do both.

public event EventHandler OnSelectedUnitChange;

vs.

public event Action OnSelectedUnitChange;

Mostly after watching this:
How To Build An Event System in Unity

So I’m mostly curious if it matters.

An Action is a simple predefined delegate with no parameters. Matching methods would be things like

void Handle_OnSelectedUnitChange()
{
   //do something
}

The event is called like this:

     if(OnSelectedUnitChange!=null)
     {
         OnSelectedUnitChange();
     }

or the better syntax which I’ll use for the rest of this post:

OnSelectedUnitChange?.Invoke(); //Combines the if check with the call, and only invokes if there are subscribers.

An alternate form of this allows you to pass one or more parameters by declaring the types

public event Action<Unit> OnSelectedUnitChange;

This method will require a signature taking in a Unit as a parameter

void HandleSelectedUnitChange(Unit unit)
{
    //Do something with the unit
}

This event would be raised like this:

OnSelectedUnitChange?.Invoke(selectedUnit); 

EventHandlers work a bit differently. They will always have two parameters, even when there are no parameters to pass…
So as declared above, the method subscribing to the event would need the parameters

object sender, EventArgs eventArgs

so

void HandleSelectedUnitChange(object sender, EventArgs eventArgs)
{
     //do something
}

and called with

HandleSelectedUnitChange?.Invoke(this, EventArgs.Empty);

Note that in all cases that an EventHandler is used without explicit parameters, you will always pass EventArgs.Empty. As such, they don’t appear any more useful than an Action.
The real power is EventHandlers is in passing parameters…
Like Actions, if you have one parameter to pass, you can use generics…

public event EventHandler<Unit> OnSelectedUnitChange;

which matches this signature:

void HandleSelectedUnitChange(object sender, Unit unit)

and is invoked with

OnSelectedUnitChange?.Invoke(this, selectedUnit);

Even this doesn’t leverage the full power of the EventHandler. If you want to pass a lot of parameters, you can create a child class of EventArgs…

public class SelectedUnitChangedArgs : EventArgs
{
    public Unit oldSelectedUnit;
    public Unit selectedUnit;
}
public event EventHandler<SelectedUnitChangedArgs> OnSelectedUnitChange;

Now the handler is:

void HandleSelectedUnitChange(object sender, SelectedUnitChangedArgs args)
{
    DoSomethingWith(args.oldSelectedUnit);
    DoSomethingElseWith(args.selectedUnit);
}

and invoked with

Unit oldSelectedUnit = selectedUnit;
selectedUnit = unitToSelect;
OnSelectedUnitChange?.Invoke(this, new SelectedUnitChangedArgs {oldSelectedUnit = oldSelectedUnit, selectedUnit = selectedUnit});
4 Likes

Oh wow. Thanks Brian!

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms