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 BakeFry 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.

 

EXPLAINING WHAT ACTION AND FUNC ARE的更多相关文章

  1. Delegate、Predicate、Action和Func

    写在前面 Delegate Predicate Action Func 逆变和协变 先说下什么是委托(Delegate),委托在C#中是一种类型,和Class是一个级别,但是我们经常把它看做是一个方法 ...

  2. VS2012 Unit Test(Void, Action, Func) —— 对无返回值、使用Action或Func作为参数、多重载的方法进行单元测试

    [提示] 1. 阅读文本前希望您具备如下知识:了解单元测试,了解Dynamic,熟悉泛型(协变与逆变)和Lambda,熟悉.NET Framework提供的 Action与Func委托.2.如果您对单 ...

  3. C#系统委托之Action And Func

    Action Action<T> Func Func<T> Action:封装一个方法,该方法不具有参数并且不返回值 public delegate void Action() ...

  4. Action<>和Func<> 委托【代理】

    C#中的Action<>和Func<> 其实他们两个都是委托[代理]的简写形式. 一.[action<>]指定那些只有输入参数,没有返回值的委托 Delegate的 ...

  5. .NET中的Action及Func泛型委托

    委托,在C#编程中占有极其重要的地位,委托可以将函数封装到委托对象中,并且多个委托可以合并为一个委托,委托对象则可以像普通对象一样被存储.传递,之后在任何时刻进行调用,因此,C#中函数回调机制的实现基 ...

  6. C#高级功能(三)Action、Func,Tuple

    Action和Func泛型委托实际上就是一个.NET Framework预定义的委托,3.5引入的特性.基本涵盖了所有常用的委托,所以一般不用用户重新声明. Action系列泛型委托,是没有返回参数的 ...

  7. 使用.NET中的Action及Func泛型委托

          委托,在C#编程中占有极其重要的地位,委托可以将函数封装到委托对象中,并且多个委托可以合并为一个委托,委托对象则可以像普通对象一样被存储.传递,之后在任何时刻进行调用,因此,C#中函数回调 ...

  8. Action 和 Func

    C# 中的两个动态委托类型 也就是说我们不用在使用委托的时候就去声明一个委托对象,而是通过Action和Func就可以模拟出我们自己要用到的委托 区别: Action 表示没有返回值的委托  例如:A ...

  9. 委托学习续:Action、Func和Predicate

    我们先看一个上一章的委托的例子: using System; using System.Collections.Generic; using System.Linq; using System.Tex ...

随机推荐

  1. mysql explain的使用(优化查询)

    explain显示了mysql如何使用索引来处理select语句以及连接表.可以帮助选择更好的索引和写出更优化的查询语句. 1.创建数据库 创建的sql语句如下: /* Navicat MySQL D ...

  2. cefsharp设置默认语言

    cefsharp是不错的浏览器内核封装版本之一,默认语言是en-US,这个一直困扰着项目,项目好多处需修改,后来经多次尝试,才发现,原来设置默认语言这么简单. CefSharp.Settings se ...

  3. Winform布局方式

    一.默认布局 ★可以加panel,也可以不加: ★通过鼠标拖动控件的方式,根据自己的想法布局.拖动控件的过程中,会有对齐的线,方便操作: ★也可选中要布局的控件,在工具栏中有对齐工具可供选择,也有调整 ...

  4. 当Python在appium中使用if……else语句不好使怎么办

    前几天写自动化脚本的时候,有个地方需要用if--else判断获得的ID和name是哪个,从而决定点击哪个按钮,我用if--else去判断,可是总是提示我找不到对应的元素, 在网上爬了好久,最终终于找到 ...

  5. 安装win7x64、x86总提示文件出错或安装大型软件出错或0x0000001a、0x0000003b蓝屏

    从不同地方下载好几个安装包,安装时候到展开文件步骤总是提示文件出错,无法安装下去. 这样可以确认不会是安装包出问题. 搜索原因,偶然看到可能与内存有关. 就检测了一遍,过程:控制面板>管理工具& ...

  6. Nginx负载均衡实践之一:基本实现

    由于现在的网站架构越来越大,基于互联网的用户也是日渐增长,所以传统的单机版服务器已经渐渐不能适应时代发展的需要.最近在和其他企业接触的过程中,发现对于互联网的经验尤为看重,所谓的互联网经验,其实就是指 ...

  7. 栈的理解以及如何计算程序所需栈的大小并在IAR中设置栈

    文章首发于浩瀚先森博客 #栈的理解 一个程序大体上讲都是由变量和函数组合而成,变量有全局变量和局部变量,还有函数间传值的参数以及返回值. Stack是为了程序运行过程中临时保存所需数据而在内存里分配的 ...

  8. Css--深入学习之三角形气泡窗

    本文是作者从别的网站和文章学习了解的知识,简单做了个笔记,想要学习更多的可以参考这里:[css进阶]伪元素的妙用--单标签之美,奇思妙想 一.三角形的实现 首先,先画了三角形,后面二.三都是根据这个 ...

  9. JavaScript之命名空间模式 浅析

    来源于:http://www.cnblogs.com/syfwhu/p/4885628.html 前言 命名空间可以被认为是唯一标识符下代码的逻辑分组.为什么会出现命名空间这一概念呢?因为可用的单词数 ...

  10. 前端代码目录结构、常用 piugin、元素补充用法及其它注意事项

    目录结构: app:  .html文件 css: .css文件 script: 脚本文件 plugin: 插件  (此目录放一些通用代码) 注意事项: 1.在IE浏览器下img会显示边框,为了保证兼容 ...