Hi everyone, in this two part series we're going to be looking delegates and events.
So actually creating a delegate is very straightforward.
We simply write the keyword 'delegate', and then, as though we were creating a method,
we specify a return type - so say void - the name of the delegate - I'll call this one
DelegateExample - and then any parameters we may want - for instance here I'll specifiy
just a single integer paramater.
We could of course have multiple parameters, in which case they'd be comma-seprated like
a normal method, or we could have no parameters at all.
Let's now make a method whose parameters and return type match those of the DelegateExample.
So a void method, which I'll call it Foo, which takes in a single integer parameter.
We can say that this method Foo is 'compatible' with DelegateExample.
Say we have a Start method, which is called when the program runs.
In here, we'll make an instance of DelegateExample, called perhaps 'myDelegate', and we can set
this equal to the Foo method, since it is compatible.
Obviously If we had another method, say 'Bar', which which was also compatible with the DelegateExample,
myDelegate could be set to Bar instead.
The point I'm trying to make is that no matter what a method does, as long as its return
type and paremeters match those specified by the delegate, we are allowed to store a
reference to it in the delegate variable.
So whichever method happens to be stored in myDelegate, in this case it's of course Bar,
we can call it writing 'myDelegate dot invoke', and supplying values for whichever paramters
the delegate specifies.
Now instead of writing dot invoke, there is a shorthand version which is just to write
double parentheses as though myDelegate were the method itself.
Behind the scenes this will call invoke, to actually call the method stored in the delegate.
Now that we can store references to methods inside a variable, this means that we can
pass methods into other methods.
So if we make one more method called 'Foobar', taking in a DelegateExample parameter, which
we can just call 'myDelegate' as well.
Then, when we call Foobar, we can pass in the myDelegate variable.
Of course it's not strictly necessary to create the myDelegate variable above, we could just
pass Foo or Bar directly pass the Foobar method.
Whichever we pass in, the Foobar method could then call it in the same way we saw previously,
by simply writing myDelegate, followed by parentheses, and passing in values for the
Now to understand why this is anything to be excited about, let's look at an example
where delegates might make our lives a little happier.
Imagine we're making sort sort of online shooter game, and we have a class called PlayerStats
which keeps track of each player's statistics throughout a round - so just things like kills,
deaths, flags captured and so forth.
When the round ends, we want to display the names of the players who were most succesfull
in different categories.
So, in the DisplayPlayerNames class, we might have an OnGameOver method, which takes in
an array of all of the player stats.
Let's start by finding the name of the player with the most kills.
We'll make a method called GetPlayerNameMostKills, returning a string for the name of the player,
and taking in the array of all player stats.
In here we'll create a string for the player name, as well as an int for the best score.
Then, looping through all the stats, we can say int score is equal to the current stats
And if the score is greater than the best score, we'll update the bestscore as well
as the name variable.
This way, when the loop has finished, we can return the player name.
So, if we now want to know the name of the player with most kills, it's as simple as
writing 'string playerNameMostKills = GetPlayerNameMostKills', and passing in all the player stats.
Next, let's make a method for finding the player with the most flag captures.
We can copy the most kills method, since it's going to be the same functionality, we just
need to change the name to most flag captures, and change the way we find the score from
'stats.kills', to 'stats.flagsCaptured'.
Now we can simply write 'string playerNameMostFlagsCaptured = GetPlayerNameMostFlagsCaptured' and pass
in all the stats.
You can imagine we might have many such methods, for all sorts of different categories.
All these methods are identical, except for how the score is determined.
This sort of situation where you've got multiple methods doing the same thing, is usually a
pretty good indications that you'll want to at least consider using delegates.
Let's delete the MostFlagsCaptured method, and at the top of the class create a delegate,
with return type int, called ScoreDelegate, which takes in a single PlayerStats parameter.
We can rename the MostKills method to something more general like 'GetPlayerNameTopScore'.
This will now take in an additional paramter, a ScoreDelegate, called something like scoreCalculator.
When we want to find the score, we now just say 'int score = scoreCalculator' passing
in the current stats variable.
This works because a scoreDelegate returns an integer, and takes in a PlayerStats.
Now lets make a ScoreByKillcount method, which returns a score integer based on the number
We can also make a ScoreByFlagCaptures method, which returns a score integer based on the
number of flagsCaptured.
Note that both of these methods are compatible with the scoreDelegate.
So now, to find the playerNames we must first of all update the method name - we changed
that to GetPlayerNameTopScore- but then we can simply pass in the scoring method we want
So in this first one I'll pass in the ScoreByKillCount, and for the second one I'll pass in ScoreByFlagCaptures.
Hopefully you'll agree that delegates have made this code a lot nicer.
This is probably a good moment to mention lambda expressions, which are based on delegates.
So if we consider our ScoreDelegate, it indicates a single input of type PlayerStats, and an
output of type int.
Thus, we can create a ScoreDelegate by writing a name for the PlayerStats input - I'll just
call it stats - followed by the lambda operator - which is an equals sign and a right angle
bracket - followed finally by the output, for example: stats.kills.
What we've written here is equivalent to our ScoreByKillcount method.
We'll look at lambda expressions more closely some other time, but what this allows us to
do is to replace the named score methods, with these inline lambda expressions.
I hope you found this video helpful.
Following on from this we'll be looking at events.
Until then, cheers.