Using delegates, func and lambdas: a tutorial with soldiers

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 childclasses 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 delegatetype:

    public delegate void SoldierAction();

Thanks to the more generic Func/Action delegates, we can remove that line in it’s entirety. Basically Func and Action are generic, parameterized delegates. Their main reason of 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 method 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 flavor!

            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 delegatemethods accept (string, Action in our case) and we’re done; no need to define a new delegatetype 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 Funcdelegate 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 accept 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.

About these ads

About timdams
C#, .NET, Microsoft, security, .... Read more on : http://timdams.com/

9 Responses to Using delegates, func and lambdas: a tutorial with soldiers

  1. threenineconsulting says:

    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!

  2. Joe says:

    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.

    • Dams Tim says:

      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?

  3. Scott says:

    That was a fun and insightful read.

  4. Douglas says:

    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.

  5. Pingback: Links van 4/05/2012 tot 16/05/2012 | The Gryphin Experience

  6. Tad says:

    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.

    • Tad says:

      Sorry my text has been html-decoded. The line I talk about is for isnatnce line 11 in Phase 5.

    • timdams says:

      Thanks Tad, apparently some typos found it’s way in the code. I think they’re fixed now. Cheerz!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 328 other followers

%d bloggers like this: