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.
- Pulling out the Switch: It’s Time for a Whooping
- Parsing Columns Like a Ninja
- The Power of Func<>
- Super Combo: Map + Function Pointer
EXPLAINING WHAT ACTION AND FUNC ARE的更多相关文章
- Delegate、Predicate、Action和Func
写在前面 Delegate Predicate Action Func 逆变和协变 先说下什么是委托(Delegate),委托在C#中是一种类型,和Class是一个级别,但是我们经常把它看做是一个方法 ...
- VS2012 Unit Test(Void, Action, Func) —— 对无返回值、使用Action或Func作为参数、多重载的方法进行单元测试
[提示] 1. 阅读文本前希望您具备如下知识:了解单元测试,了解Dynamic,熟悉泛型(协变与逆变)和Lambda,熟悉.NET Framework提供的 Action与Func委托.2.如果您对单 ...
- C#系统委托之Action And Func
Action Action<T> Func Func<T> Action:封装一个方法,该方法不具有参数并且不返回值 public delegate void Action() ...
- Action<>和Func<> 委托【代理】
C#中的Action<>和Func<> 其实他们两个都是委托[代理]的简写形式. 一.[action<>]指定那些只有输入参数,没有返回值的委托 Delegate的 ...
- .NET中的Action及Func泛型委托
委托,在C#编程中占有极其重要的地位,委托可以将函数封装到委托对象中,并且多个委托可以合并为一个委托,委托对象则可以像普通对象一样被存储.传递,之后在任何时刻进行调用,因此,C#中函数回调机制的实现基 ...
- C#高级功能(三)Action、Func,Tuple
Action和Func泛型委托实际上就是一个.NET Framework预定义的委托,3.5引入的特性.基本涵盖了所有常用的委托,所以一般不用用户重新声明. Action系列泛型委托,是没有返回参数的 ...
- 使用.NET中的Action及Func泛型委托
委托,在C#编程中占有极其重要的地位,委托可以将函数封装到委托对象中,并且多个委托可以合并为一个委托,委托对象则可以像普通对象一样被存储.传递,之后在任何时刻进行调用,因此,C#中函数回调 ...
- Action 和 Func
C# 中的两个动态委托类型 也就是说我们不用在使用委托的时候就去声明一个委托对象,而是通过Action和Func就可以模拟出我们自己要用到的委托 区别: Action 表示没有返回值的委托 例如:A ...
- 委托学习续:Action、Func和Predicate
我们先看一个上一章的委托的例子: using System; using System.Collections.Generic; using System.Linq; using System.Tex ...
随机推荐
- Android开发究竟用什么工具,Eclipse||AS
所谓公欲善其事必先利器,那就让我们来看一下android的开发工具吧,安卓的开发工具有Eclipse和Android Studio,另外还有IntelliJ IDEA,可能很多人并不知道. 首先看一下 ...
- [diango]理解django视图工作原理
前言:正确理解django视图view,模型model,模板的概念及其之间的关联关系,才能快速学习并上手使用django制作网页 本文主要讲解自己在学习django后对视图view的理解 在进入正文之 ...
- 理解ThreadLocal(之二)
想必很多朋友对ThreadLocal并不陌生,今天我们就来一起探讨下ThreadLocal的使用方法和实现原理.首先,本文先谈一下对ThreadLocal的理解,然后根据ThreadLocal类的源码 ...
- log4j.properties配置详解
1.Loggers Loggers组件在此系统中被分为五个级别:DEBUG.INFO.WARN.ERROR和FATAL.这五个级别是有顺序的,DEBUG < INFO < WARN < ...
- NOIP模拟赛20161114
幸运串 题意:长度为n,字符集大小为m的字符串中有多少不同的不含回文的串 n,m<10^9 我靠这不就是萌数的DP部分吗 有规律 f[2][j][k]=1 f[i][j][k]=sigma{f[ ...
- kettle运行spoon.bat时找不到javaw文件
我也遇到这问题了,分享一下解决方法吧以后没准还有人能用到.我机器的主要问题是环境变量JAVA_HOME的值不对,应该写到jdk也就是C:\Program Files\Java\jdk1.7.0_25, ...
- C#.NET 大型企业信息化系统集成快速开发平台 4.2 版本 - 访问频率限制功能实现、防止黑客扫描、防止恶意刷屏
很多软件组件,大家都能想到了,大家也能做出来,但是成熟稳定.可靠.易用.功能全面,可信任,可相信,可开源就不是很容易,需要树立良好的口碑才可以. 1:往往会有黑客,进行撞库挖掘漏洞,很多系统的账户有可 ...
- 2016-1-1最新版本的linphone-android在mac上编译通过,同时建立了IDEA工程
虽然参考了这个文章<MAC OS编译Android版Linphone SDK和APP>,https://www.lidaren.com/archives/1592 ,但是在实际的编译过程中 ...
- ionic 开发笔记
1.AngularJS 外部的控制器(DOM 事件.外部的回调函数如 jQuery UI 空间等)调用了 AngularJS 函数之后,必须调用$apply.在这种情况下,你需要命令 AngularJ ...
- JavaScript模板引擎artTemplate.js——如何引入模板引擎?
artTeamplate.js在github上的地址:artTemplate性能卓越的js模板引擎 引入模板引擎,就是引入外部javascript啦,并且artTemplate.js不依赖其他第三方库 ...