In this tutorial, written for beginning programmers, I’d like to show a little demonstration on the usage of delegates and how we can go all crazy by refactoring and magically see all our duplicate code disappear.
Imagine we are writing the next ultimate Command&Conquer spinoff which can run on any computer …in console-mode. Now imagine that in the early phases of our prototype we create a Soldier class: all soldiers should be able to simply “Do their thing” when asked to do so. When they do, they should report on what they do, of course. Typical “DoYourThing” actions might include throwing a grenade, cowardly running away or going into Full Rambo-mode:
Phase 1: Oldschool coding
Smart as a cookie, we create our Soldier class:
class Soldier { public Soldier(string name) { Name = name; } public string Name { get; set; } public virtual void DoYourThing() { //Let the inherited soldiers do their thing } }
Look how smart. We made our DoYourThing() method virtual, allowing us to create an over-the-top amount of Soldier child classes that all override the method with the specific action that Soldier can do.
Mmm…but all these inherited classes (GrenadeSoldier, RamboSoldier, etc.) are blowing out of proportion and contain 99% duplicate code.
Phase 1.2 or 1.1
Depending on your train of thought, you might first have done this step or first the previous one and then this one. Anyhow, let’s be a smarter cookie and don’t go for inheritance and simply write a switch:
class Soldier { public Soldier(string name, int actionin) { Name = name; ActionNumber = actionin; } public string Name { get; set; } public int ActionNumber { get; private set; } public virtual void DoYourThing() { switch(ActionNumer) { case 1: Console.WriteLine(Name + ":Thowing a grenade."); break; //.. } } }
Again, we’ll ignore the obvious improvement of making this ActionNumber into an enum, but as you might have guessed, this still ain’t the right way.
Phase 2: On with the delegates
Since this tutorial about delegates, let’s try to refactor our code so that delegates start showing their worth.
It’d be much handier if we could keep the implementation of the different actions a soldier can do outside the Soldier class itself. Imagine that in a future update of your game you’d like to add new cool soldiers and/or their actions, if we keep the everything tightly bound (i.e. keep the actions inside the soldier) we’d have to recompile our entire Soldier class. So, out with the Soldier actions, in with delegates!
public delegate void SoldierAction(); class Soldier { public Soldier(string name, SoldierAction actionin) { Name = name; Action = actionin; } public string Name { get; set; } public SoldierAction Action { get; private set; } public virtual void DoYourThing() { Action(); } }
So we defined a new SoldierAction delegate which we’ll use as our vehicle to ‘give’ the action-implementation to the soldier. Notice that we basically changed the type of our ActionNumber from int to the newly creates SoldierAction delegate type (and gave it a slightly improved name).
Imagine now that we moved the different actions to self-contained methods, outside the Soldier class:
public static void RamboStyle() { Console.WriteLine("Kill'm all!"); }
We now can create cute little Rambo’s and other types that will do the actions they were made for:
Soldier rambo = new Soldier("John", new SoldierAction(RamboAction)); rambo.DoYourThing();
Notice that IntelliSense (or is it Resharper?) is kind enough to point out that we could also write:
Soldier rambo = new Soldier("John", RamboAction);
For all you lambda lovers out there: suppose every action will be totally different and writing a method for each action would be overhead, we could also write:
Soldier rambo = new Soldier("John", () => {Console.WriteLine("Come get some");});
Phase 3: Enter Action<T>
In the previous refactor, we explicitly defined a new delegate type:
public delegate void SoldierAction();
Thanks to the more generic Func/Action delegates, we can remove that line in its entirety. Basically, Func and Action are generic, parameterized delegates. Their main reason for existence is simply to remove lines like the one just mentioned in which we explicitly define a new delegate.
First, let’s see what the main difference is between Func and Action:
- Func delegates are used to encapsulate methods that return a value.
- Action delegates are used to encapsulate methods that return void.
Now, being the lazy bum that I am: check out this excellent tutorial on the basics of both Func and Action delegates. I can’t explain it any better than they do, so hop to that site, read it all and come back here. I can wait.
Since our soldier actions return void, we’ll go for the Actiondelegate. However, because no parameters are provided we can use the non-generic one. Our refactored class becomes (and we delete the SoldierAction delegate definition):
class Soldier { public Soldier(string name, Action actionin) { Name = name; Action = actionin; } public string Name { get; set; } public Action Action { get; private set; } public virtual void DoYourThing() { Action(); } }
Note that we don’t have to change anything in the way we need to instantiate new Soldier objects.
Phase 4: Bring in the soldiers
With this done. We can now create vast armies of soldiers doing their thing:
var soldiers = new List<Soldier>() { new Soldier("Joey", CowardAction), new Soldier("Carnie", GrenadeThrowerAction), new Soldier("John", RamboAction), }; foreach (var soldier in soldiers) { soldier.DoYourThing(); }
Immediately our duplicate code alarm goes into overdrive. Now what? Well, just for the sake of completeness. Let’s try to make those 3 lines in which we add new soldiers shorter, because, be honest, they are 90% identical (don’t start calculating this percentage please).
Let’s wrap the ‘action’ of creating new soldiers and putting them in our list into…you’ll never guess it….Wait for it. ..Yup, let’s wrap it into an Action delegate! And for the sake of being ubercool (hey we are writing C&C after all), we’ll add in some samba…I mean lambda flavour!
Action<string, Action> fastSoldierMaker = (name, action) => soldiers.Add(new Soldier(name, action)); fastSoldierMaker("Joey", CowardAction); fastSoldierMaker("Carnie", GrenadeThrowerAction); fastSoldierMaker("John", RamboAction);
Now, to be honest. This last example was mainly introduced to show how we can define generic delegates: we simply state what parameters the delegate methods accept (string, Action in our case) and we’re done; no need to define a new delegate type first.
Phase 5: Barracks to do the hard work
How could we use our new fastSoldierMaker delegate? Imagine we have several Barracks, each which creates a specific type of soldier. We could pass the fastSoldierMaker to each barrack when it is constructed: each created soldier will automatically be added to our full list soldiers:
class Barrack { public void MakeUnit() { if (BuildAction != null) { BuildAction("somedude", TypeOfSoldiers); } } public Action<string, Action> BuildAction { get; set; } public Action TypeOfSoldiers { get; set; } }
I leave it up to you to create a nifty random name generator for each soldier.
Next, we can now do something like:
var soldiers = new List<Soldier>(); Action<string, Action> fastSoldierMaker = (name, action) => soldiers.Add(new Soldier(name, action)); var cowardCreatorBarrack = new Barrack() {BuildAction = fastSoldierMaker, TypeOfSoldiers = CowardAction }; cowardCreatorBarrack.MakeUnit();
Phase 5.1: Refactoring barracks to add some Func
Did you just see what I did there? Funny huh. *cough* As one of my reviewers kindly pointed out: a) my barracks could do a bit more work, resulting in less work on the outside, and b) I haven’t shown how the generic Func delegate can be used.
Imagine we create a Func delegate inside the barracks which we’ll use to create a soldier with a given name. We can than afterwards change, for example, the type of soldier to create.
private Func<string, Soldier> createUnitFunction;
What we state here is that the createUnitFunction is a delegate for any method that accepts one string parameter and returns a Soldier.
Next stop, we’ll add a nice constructor to which we’ll pass the type of soldier to create and the list to which the created soldier should be added to. Resulting in (thanks Hannes Lowette from Axxes):
class Barrack { private Func<string, Soldier> createUnitFunction; public Barrack(ICollection soldiers, Action typeOfSoldier) { Soldiers = soldiers; TypeOfSoldier = typeOfSoldier; createUnitFunction = (name) => (new Soldier(name, TypeOfSoldier)); } public Action TypeOfSoldier { get; private set; } public ICollection<Soldier> Soldiers { get; private set; } public void MakeUnit() { if (createUnitFunction != null) { Soldiers.Add(createUnitFunction("somedude")); } } }
We can then simplify our soldier creating code:
var soldiers = new List<Soldier>(); var cowardCreatorBarrack = new Barrack(soldiers, CowardAction); cowardCreatorBarrack.MakeUnit();
Conclusion
So, that’s it for now. Hope you’ve felt a bit of ‘the force’ of using delegates and their more modern generic counterparts. (yeah, I don’t like to write conclusion… they tend to repeat what was said before).
A special thanks to Glenn Ergeerts (Artesis) and Hannes Lowette (Axxes) for reviewing this.
This is a great article. In truth it really helped me gain a further enhanced understanding of Func and Action Delegates, the reference to the Black Wasp article was also an exceptional read! This all sits very clearly in my mind right now! Lets see if it’s all still there in morning when I would be looking to implement it 🙂
Great work look forward to reading more!
LikeLike
This is a great article… I am new to Action and Func Delegates. I have a question though. How do you reference soldier Properties from the Action. For example lets say you want your DoYourThink to log that your soldier has started walking. If it were a local method of soldier you could just say something like ‘Log.Write(Name + ” started walking”);’ But since it is an Action you don’t have access to the Property… do you? So how would you define an Action that uses the Name Property? I hope my question makes sense.
LikeLike
Hi Joe,
Guess you’d have to wrap the Action in a class which will include some ‘Description’ kind of property of the action. You could then add logging logic in that class or in the Soldier-DoAction() method. Perhaps anyone else has other ideas?
LikeLike
That was a fun and insightful read.
LikeLike
Very nice! I’ve already been using delegates, but this helped me get a better understanding of them so that maybe I can use them in more beneficial ways. Thank you.
LikeLike
I like the article, however I can’t figure out what lines like this are meant to be
public Action BuildAction { get; set; }
The complier does not accept: action=”” there.
So in the end I really got stuck on step 4.
LikeLike
Sorry my text has been html-decoded. The line I talk about is for isnatnce line 11 in Phase 5.
LikeLike
Thanks Tad, apparently some typos found it’s way in the code. I think they’re fixed now. Cheerz!
LikeLike
Hello ! A long time after this soldier production begun, I have a proposal : let the Soldier Type to be Generic.
Let’s start with a bunch of interfaces (I love interfaces) :
<code>
interface IActionable
{
Action Action { get; set; }
}
interface INamed
{
string Name { get; set; }
}
interface INamedActionable : IActionable, INamed
{
}
</code>
Then, we go for this kind of “generic-typed” Barrack (I had to rename “TypeOfSoldier” into “Action” to greatly reuse the IActionable interface), that will accept any kind of T, at the condition of T being :
1) Inheriting INamedActionable, to make sure it will accept a Name + an Action (unnameable or unactionable Soldiers won’t be Barrackable)
2) Newable (for the sake of newability)
<code>
class Barrack<T> : IActionable
where T : INamedActionable, new()
{
private readonly Func<string, T> createUnitFunction;
public Barrack(ICollection<T> soldiers, Action typeOfSoldier)
{
Soldiers = soldiers;
Action = typeOfSoldier;
createUnitFunction = (name) => new T() { Name = name, Action = typeOfSoldier };
}
public ICollection<T> Soldiers { get; private set; }
public Action Action { get; set; }
public void MakeUnit()
{
if (createUnitFunction != null)
{
Soldiers.Add(createUnitFunction(NameGenerator()));
}
}
private string NameGenerator()
{
if (true) // Smart random selector
return “somedude”;
else
return “John”;
}
}
</code>
And now, the Soldier class just inherits the INamedActionable to be barrackable.
<code>
class Soldier : INamedActionable
{
public Soldier(string name, Action actionin)
{
Name = name;
Action = actionin;
}
public string Name { get; set; }
public Action Action { get; set; }
public virtual void DoYourThing()
{
Action();
}
}
</code>
To have some more fun, we could keep on the C&C tracks, and prepare one brand new TiberiumPlane class :
<code>
class TiberiumPlane : INamedActionable
{
public TiberiumPlane(string name, Action actionin)
{
Name = name;
Action = actionin;
}
public string Name { get; set; }
public Action Action { get; set; }
public virtual void Fly()
{
Action();
}
}
</code>
Now, we can prepare the troops like this :
<code>
var troops = new List<Soldier>();
var cowardCreatorBarrack = new Barrack<Soldier>(troops, () => Console.WriteLine(“There’s no place like Home.”));
cowardCreatorBarrack.MakeUnit();
var flyings = new List<TiberiumPlane>();
var planeCreatorBarrack = new Barrack<TiberiumPlane>(flyings, () => Console.WriteLine(“Fly, Little One!”));
planeCreatorBarrack.MakeUnit();
</code>
——-
Okay, my Soldier and TiberiumPlane classes are 2/3 same code, they should inherit something more common like an abstract Troop thing, or alike :
<code>
class Soldier : Troop
{
public Soldier(string name, Action actionin) : base(name, actionin)
{
}
public virtual void DoYourThing()
{
Action();
}
}
class TiberiumPlane : Troop
{
public TiberiumPlane(string name, Action actionin) : base(name, actionin)
{
}
public virtual void Fly()
{
Action();
}
}
abstract class Troop : INamedActionable
{
public string Name { get; set; }
public Action Action { get; set; }
public Troop(string name, Action actionin)
{
Name = name;
Action = actionin;
}
}
</code>
——-
And with the upcoming C#8 Default Interface Methods, the troops will have no effort to Act on theirselves, based on default instructions :
<code>
interface IDoYourThingable : IActionable
{
void DoYourThing() { Action?.Invoke(); }
}
class Soldier : Troop, IDoYourThingable
{
public Soldier(string name, Action actionin) : base(name, actionin)
{
}
}
interface IFlyable : IActionable
{
void Fly() { Action?.Invoke(); }
}
class TiberiumPlane : Troop, IFlyable
{
public TiberiumPlane(string name, Action actionin) : base(name, actionin)
{
}
}
</code>
Yeeks, that was a long one, sorry, and was hardly relevant with delegates and lambdas… But that showed how to use Generics with those two, also with a fair use of DIMs !
LikeLike
Some extension points :
– Barracks keep internal tracks of their own barracked units, there is no need to define it externally at the moment ;
– Text written in the Console looks like a response to something, so I made it clear with the Response name + Respond() method ;
– Soldiers and Planes all respond the same (writing text to the Console), I changed this to have a TiberiumPlane dropping a Soldier ;
– Any unit would have to react the same (corwardly, plane-y, …) depending on its real type, a specific by-type response is implemented (away from the Barrack)
Little has changed in the interfaces:
<code>
interface IRespondable<ResponseType>
{
Action<ResponseType> Response { get; set; }
ResponseType ResponseParam { get; set; }
}
interface INamed
{
string Name { get; set; }
}
interface INamedRespondable<ResponseType> : IRespondable<ResponseType>, INamed
{
void Respond();
}
</code>
Barrack class is simplified:
<code>
class Barrack<T, ResponseType>
where T : INamedRespondable<ResponseType>, new()
{
private readonly Func<string, T> createUnitFunction;
public IList<T> BarrackedUnits { get; private set; }
public Barrack()
{
BarrackedUnits = new List<T>();
createUnitFunction = (name) => new T() { Name = name };
}
public void MakeUnit()
{
if (createUnitFunction != null)
BarrackedUnits.Add(createUnitFunction(NameGenerator()));
}
private string NameGenerator()
{
if (typeof(T) == typeof(TiberiumPlane)) // Smart random selector
return “Elton”;
else
return “John”;
}
}
</code>
Unit classes simplified, and have a type-specialized response:
<code>
class Soldier : Troop<string>
{
public Soldier()
{
ResponseParam = “Anotherone One Bites the Dust.”;
}
}
class CowardSoldier : Soldier
{
public CowardSoldier()
{
ResponseParam = “There’s no place like Home.”;
}
}
class TiberiumPlane : Troop<Soldier>
{
public TiberiumPlane()
{
Ship(new Soldier() { Name = “Dropping”, ResponseParam = “Fly, My Little!” });
Response = (ResponseParam) =>
{
//<- Set the Log here
ResponseParam.Respond();
};
}
public void Ship(Soldier soldier)
{
Console.WriteLine($”Welcome aboard, {soldier.Name}.”);
ResponseParam = soldier;
}
}
abstract class Troop<ResponseType> : INamedRespondable<ResponseType>
{
public string Name { get; set; }
public Action<ResponseType> Response { get; set; }
public ResponseType ResponseParam { get; set; }
public Troop()
{
Response = (ResponseParam) => Console.WriteLine(ResponseParam);
}
public virtual void Respond()
{
//<- Set the Log here
Console.WriteLine($”{Name} here!”);
Response?.Invoke(ResponseParam);
}
}
</code>
Now, how to use this version:
<code>
var cowardCreatorBarrack = new Barrack();
cowardCreatorBarrack.MakeUnit();
var planeCreatorBarrack = new Barrack();
planeCreatorBarrack.MakeUnit();
planeCreatorBarrack.MakeUnit(); // Make a second TiberiumPlane unit
Console.WriteLine(“-“);
planeCreatorBarrack.BarrackedUnits[1].Ship(cowardCreatorBarrack.BarrackedUnits[0]); // Ship the first CowardSoldier unit into the second TiberiumPlane unit
foreach (var unit in planeCreatorBarrack.BarrackedUnits)
{
Console.WriteLine(“-“);
unit.Respond();
}
Console.ReadKey();
// Result:
/*
* Welcome aboard, Dropping.
* Welcome aboard, Dropping.
* –
* Welcome aboard, John.
* –
* Elton here!
* Dropping here!
* Fly, My Little!
* –
* Elton here!
* John here!
* There’s no place like Home.
*/
</code>
Action lambda-overrided with a generic typed Barrack. Sorry for the mess, I just wanted to add small things and ended up with this.
LikeLike
The last code part was HTML-marked down…
<code>
var cowardCreatorBarrack = new Barrack<CowardSoldier, string>();
cowardCreatorBarrack.MakeUnit();
var planeCreatorBarrack = new Barrack<TiberiumPlane, Soldier>();
planeCreatorBarrack.MakeUnit();
planeCreatorBarrack.MakeUnit(); // Make a second TiberiumPlane unit
planeCreatorBarrack.BarrackedUnits[1].Ship(cowardCreatorBarrack.BarrackedUnits[0]); // Ship the first CowardSoldier unit into the second TiberiumPlane unit
foreach (var unit in planeCreatorBarrack.BarrackedUnits)
{
Console.WriteLine(“-“);
unit.Respond();
}
Console.ReadKey();
// Expected result:
/*
* Welcome aboard, Dropping.
* Welcome aboard, Dropping.
* Welcome aboard, John.
* –
* Elton here!
* Dropping here!
* Fly, My Little!
* –
* Elton here!
* John here!
* There’s no place like Home.
*/
</code>
LikeLike