zoukankan      html  css  js  c++  java
  • EXPLAINING WHAT ACTION AND FUNC ARE

    http://simpleprogrammer.com/2010/09/24/explaining-what-action-and-func-are/

     

    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.  Let’s 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, int> 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.  Funcs 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.

    Further Resources for Action and Func

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

  • 相关阅读:
    oracle 查询 当前最大时间的value的值
    Visual Studio《加载此属性页时出错》的解决办法
    (转) 关于在IE6下 无法跳转问题
    LINQ TO XML 个人的一些心得1
    CSS实现单行、多行文本溢出显示省略号(…)
    html 图像映射(一个图像多个连接)
    JS页面跳转大全
    首行负缩进达到内容对齐的目的
    HTML图片死活不显示
    JS高级. 06 缓存、分析解决递归斐波那契数列、jQuery缓存、沙箱、函数的四种调用方式、call和apply修改函数调用方法
  • 原文地址:https://www.cnblogs.com/dufu/p/4279511.html
Copyright © 2011-2022 走看看