Advertisements
Posted by: jsonmez | September 24, 2010

Explaining What Action<> And Func<> Are

In C#, Action<> and Func<> are extremely useful tools for reducing duplication in code and decreasing coupling.

It is a shame that many developers shy away from them, because they don’t really understand them.

Adding Action<> and Func<> to your toolbox is a very important step in improving your C# code.

It’s not really that hard to understand what they do and how to use them, it just takes a little patience…

A simple way of thinking about Action<>

Most of us are pretty familiar with finding sections of repeated code, pulling that code out into a method and making that method take parameters to represent the differences.

Here is a small example, which should look pretty familiar:

public void SteamGreenBeans()
{
    var greenBeans = new GreenBeans();
    Clean(greenBeans);
    Steam(greenBeans, Minutes.Is(10));
    Serve(greenBeans);
}

public void SteamCorn()
{
    var corn = new Corn();
    Clean(corn);
    Steam(corn, Minutes.Is(15));
    Serve(corn);
}

public void SteamSpinach()
{
    var spinach = new Spinach();
    Clean(spinach);
    SteamVegetable(spinach, Minutes.Is(8));
    Serve(spinach);
}

Each one of these methods pretty much does the same thing.  The only difference here is the type of vegetable and the time to steam it.

It is a simple and common refactor to refactor that code to:

public void SteamGreenBeans()
{
   SteamVegetable(new GreenBeans(), 10);
}

public void SteamCorn()
{
    SteamVegetable(new Corn(), 15);
}

public void SteamSpinach()
{
    SteamVegetable(new Spinach(), 8);
}

public void SteamVegetable(Vegetable vegetable, int timeInMinutes)
{
    Clean(vegetable);
    Steam(vegetable, Minutes.Is(timeInMinutes));
    Serve(vegetable);
}

Much better, now we aren’t repeating the “actions” in 3 different methods.

Now let’s imagine we want to do something more than steam.  We need to be able to fry or bake the vegetables.  How can we do that?

Probably we will have to add some new methods for doing that.  So we will end up with something like this:

public void SteamVegetable(Vegetable vegetable, int timeInMinutes)
{
    Clean(vegetable);
    Steam(vegetable, Minutes.Is(timeInMinutes));
    Serve(vegetable);
}

public void FryVegetable(Vegetable vegetable, int timeInMinutes)
{
    Clean(vegetable);
    Fry(vegetable, Minutes.Is(timeInMinutes));
    Serve(vegetable);
}

public void BakeVegetable(Vegetable vegetable, int timeInMinutes)
{
   Clean(vegetable);
   Bake(vegetable, Minutes.Is(timeInMinutes));
   Serve(vegetable);
}

Hmm, lots of duplication again.  No problem.  Lets just do what we did to the first set of methods and make a CookVegetable method.  Since we always clean, then cook, then serve, we should be able to just pass in the method of cooking we will use.

Oh wait, how do we do that?  We can’t just extract out Bake or Fry or Steam, because the Bake, Fry and Steam methods are logic and not data.

Unless… unless we can make them data.  Can we do that?

We sure can, check this out:

public void SteamVegetable(Vegetable vegetable, int timeInMinutes)
{
    CookVegetable(vegetable, Steam, timeInMinutes);
}

public void FryVegetable(Vegetable vegetable, int timeInMinutes)
{
    CookVegetable(vegetable, Fry, timeInMinutes);
}

public void BakeVegetable(Vegetable vegetable, int timeInMinutes)
{
    CookVegetable(vegetable, Bake, timeInMinutes);
}

public void CookVegetable(Vegetable vegetable,
   Action<Vegetable, CookingTime> cookingAction,
   int timeInMinutes)
{
    Clean(vegetable);
    cookingAction(vegetable, Minutes.Is(timeInMinutes));
    Serve(vegetable);
}

We got rid of the duplicated code the same way we did when we did our first refactor, except this time we parameterized method calls instead of data.

If you understood this, you understand Action<>.  Action<> is just a way of treating methods like they are data. Now you can extract all of the common logic into a method and pass in data that changes as well as actions that change.

Congratulations, you are doing the strategy pattern without having to create an abstract base class and a huge inheritance tree!

So when you see Action<>, just think “ah, that means I am passing a method as data.”

It really is as simple as that.

Action<Vegetable, CookingTime> translated to English is: “A method that takes a Vegetable and a CookingTime as parameters and returns void.”

What about Func<>?

If you understand Action<>, you understand Func<>.

Func<X, Y, Z> translated to English is: “A method that takes an X, and a Y as parameters and returns a Z”.”

The only difference between Action<> and Func<> is that Func<>’s last template parameter is the return type.  Func<>s have non-void return values.

Bonus: Predicate<> is a Func<> that always returns a boolean.

That’s all there is to it.  There really isn’t a need to know much more than that to make sure of Action<> and Func<> in order to start using them.

If you are interested in some other ways to apply Action<> and Func<>, here are some posts I have written which focus on them.

As always, you can subscribe to this RSS feed to follow my posts on Making the Complex Simple.  Feel free to check out ElegantCode.com where I post about the topic of writing elegant code about once a week.  Also, you can follow me on twitter here.
Advertisements

Responses

  1. Very well put and very simple clear example. Although I had used all of these before I thought the simplified explanation gave me a very good way to remember the differences and explain it to others.

  2. Interesting article. It took me a bit to figure out the Action but your example helped me picture useful scenarios for it.

    I am still a little confused about Func
    For example:
    Func myMultiplyFunction = (a,b) => a * b;

    and

    public delegate int twoNumberCalculator(int arg, int arg2);
    twoNumberCalculator multiplyTwoNumbers = (a, b) => a * b;

    Is Func just a shortcut or are there scenarios where one will be chosen of the other?

    • It is basically the same as a delegate. In fact Func is a delegate itself.

  3. Ack the comment box stole part of my code:

    I meant:

    Func myMultiplyFunction = (a,b) => a * b;

  4. […] Explaining What Action<> And Func<>; Are – John Sonmez highlights the Action<> and Func<> types and explains why they are so useful, particularly for dealing with situations where you have code duplication caused by common code wrapping specific functionality. […]

  5. Very solid post. Clear and simple!

  6. One of the best explanations I have read. Simple, real world and concise.

    • Thanks for the compliment, glad to be of help.

    • At last! Someone with the insight to solve the prolbem!

  7. […] you’re not familiar with Action<> take a look at this post I did that gives a very simple explanation for how it […]

  8. […] void are named Action, but looks almost identical). These generic delegates can even be put to use in your own programs to not only parameterize methods by value but by […]

  9. […] that return void, named Action, and those that don’t, named Func. You can use these delegates in your own code to not only parameterize methods by value but by […]

  10. […] Explaining What Action And Func Are « Making the Complex Simple: […]

  11. This is a great 2-for-1 deal here.
    The sequence of steps in the example distill the purpose of Action and make Func plainly obvious in the end.

    Many thanks.

  12. wow, first article which explain not how to use it, but when to use it. Thx!

  13. Amazing! you explained the problem and then worked backwards from there…excellent way to teach ;]

    Thank you

  14. Very good and well explained! it helped me a lot. thanks! keep it up.

    simple and easy to understand.

  15. Probably one of the most straightforward and easy to understand posts I’ve ever come across.

    Simply fantastic post.

    • Thanks Charles!

  16. great article!! it helped me a lot, and very simple!

  17. I just want to say … thank you

    • Your welcome!

  18. Excelente post , de verdad que has logrado conseguir algo que ha simple vista parece complejo, explicarlo de forma sencilla. =) sigue asi exitos.

  19. […] You will need to understand how Action works though.  If you don’t, check out this post I did explaining Action and Func. […]

  20. Great post! finally understand what is really Func

  21. Thanks a lot. It was very helpful.

  22. Perfect! I sort of understood it before, but I wasn’t 100% sure. Got it now and it’s working perfectly 🙂 Thanks!

  23. Simple and good explanation….!!!

  24. Best one

  25. Great explanation! Thanks!

  26. Great Article, well explained.. Thanks !

  27. …literally simply.. amazing mate !

    Thanks !

  28. Good post!

  29. Neatly explained, thnx

  30. Very useful, thanks for sharing

  31. Superb Explanation…

  32. Simple and to the point. Just how I like it

  33. Hey what does minutes.is do while calling the cookingaction. ?

    • It just is a class Minutes with a static method Is that returns back an instance of a Minutes object. Makes the code read better and allows for validation on Minutes.

  34. Woah! I’m really digging the template/theme of this website. It’s
    simple, yet effective. A lot of times it’s tough to get that “perfect balance” between user friendliness and visual appearance. I must say you’ve done
    a very good job with this. Additionally, the blog loads super quick for me on Chrome.
    Excellent Blog!


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

Categories

%d bloggers like this: