c#如何使用Action和Func_c#Action和Func从入门到精通教程
C#中的Action与Func:从“天天见”到“真正会用”

免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈
开门见山,先说一个核心判断:Action 和 Func 压根不是什么需要“学透”才能用的高级概念。恰恰相反,它们是C#世界里最基础、最常用的委托类型,日常开发中处理事件、异步回调、LINQ查询或是依赖注入配置时,几乎天天都会打照面。真正让开发者感到困惑的,往往不是语法本身,而是两个更实际的问题:“眼下这个场景,我到底该用哪个?” 以及 “Func的参数顺序,到底该怎么记才不容易错?”。
什么时候必须用 Action,而不是自己写委托?
简单来说,Action 就是那个“只负责执行、不关心返回值”的委托标准件。当你需要定义一个 delegate void DoSomething(string s, int i) 时,与其从头手写,不如直接使用 Action。编译器在背后已经为你做好了所有映射,而且整个.NET基础库(比如 List 方法、Task.Run 方法)都认它,兼容性和通用性直接拉满。
- 典型应用场景:按钮的点击事件
button.Click += (s, e) => { ... },其本质就是Action的一种变体;而Task.Run(() => Console.WriteLine("done"))里用到的,正是无参数的Action。 - 注意参数上限:系统预定义的
Action最多支持16个泛型参数(从Action到Action)。一旦超过这个数量,抱歉,你就得回归老路,自己动手定义委托了。 - 给个实用建议:除非你需要多次复用同一个委托签名,并且希望给它起一个清晰易懂的名字(例如
public delegate void LogHandler(string msg);),否则,自己手写delegate纯属增加无谓的代码量。
Func 的返回值类型总在最后,这是硬规则
关于 Func,有一条铁律必须刻在脑子里:它的泛型参数列表中,最后一个类型参数,一定是返回值类型,前面的所有类型才是输入参数。这个顺序一旦搞错,编译器会毫不客气地抛出 CS0411 错误。
- 反面教材:想表达“输入一个int,返回一个string”,正确的写法是
Func。如果一不小心写成了Func,语义就完全反了,变成了“输入string,返回int”。 - 无参但有返回值:这时候就用
Func。比如,Func表示一个调用后会返回字符串的方法。这种形式在实现延迟计算时特别有用,例如:var lazyName = new Lazy。(() => GetNameFromDb()); - 一个关键限制:
Func必须要有返回值类型。所以,Func是非法语法。如果你的方法什么都不想返回,请直接去找Action。
传参时捕获变量要注意生命周期
使用lambda表达式来创建 Action 或 Func 时,如果lambda内部引用了外部的局部变量,一个经典的“闭包陷阱”可能正在等着你。比如下面这个例子:
var actions = new List(); for (int i = 0; i < 3; i++) { actions.Add(() => Console.WriteLine(i)); // 小心!这里全部会输出 3! } foreach (var a in actions) a();
- 问题根源:lambda表达式捕获的是变量
i的引用,而不是在循环每个迭代时的瞬时值。当循环结束时,i的值已经变成了3,此时所有存储在列表中的Action再去读取i,看到的自然都是这个最终值。 - 标准修复方案:在循环体内部声明一个局部变量,让lambda捕获这个“快照”。
for (int i = 0; i < 3; i++) { int localI = i; actions.Add(() => Console.WriteLine(localI)); } - 需要留意:在C# 5及更高版本中,
foreach循环的迭代变量默认已经按值捕获了,但这个“福利”并没有惠及传统的for循环,后者仍需手动处理。
话说回来,还有一个容易被忽略的高级特性——委托的协变与逆变。举个例子,Func 能直接赋值给 Func 吗?答案是不能。但反过来,Func 却可以赋值给 Func(因为string是object的子类,返回值类型支持协变)。这类细节在平常简单的委托调用中并不显眼,可一旦涉及到复杂的泛型委托转换或者框架接口设计时,它们就会突然变得至关重要。
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
怎么利用 System.err 输出错误流并在控制台中以醒目的颜色标记(取决于终端)
怎么利用 System err 输出错误流并在控制台中以醒目的颜色标记(取决于终端) System err 默认行为不带颜色,终端是否显示颜色取决于自身支持 首先得明确一点:System err 本质上只是 Ja va 标准库里的一个 PrintStream 对象。它本身并不负责“颜色”这种花哨的玩
如何在 Java 中使用 ThreadLocal.remove() 确保在线程池复用场景下不会发生数据污染
如何在 Ja va 中使用 ThreadLocal remove() 确保在线程池复用场景下不会发生数据污染 说到线程池和 ThreadLocal 的搭配使用,一个看似不起眼、实则极易“踩坑”的细节就是数据清理。想象一下,你精心设计的线程池正在高效运转,却因为某个任务留下的“数据尾巴”,导致后续任务
怎么利用 Arrays.asList() 转换出的“受限列表”理解其对 add() 等修改操作的限制
Arrays asList():一个“受限”但实用的列表视图 在Ja va开发中,Arrays asList()是一个高频使用的方法,但你是否真正了解它返回的是什么?一个常见的误解是,它直接生成了一个标准的ArrayList。事实并非如此。 简单来说,Arrays asList()返回的并非我们熟悉
如何在 Java 中利用 try-catch 实现对“软错误”的平滑感知与非侵入式监控日志记录
如何在 Ja va 中利用 try-catch 实现对“软错误”的平滑感知与非侵入式监控日志记录 在 Ja va 开发中,我们常常会遇到一些“软错误”——它们不会让程序直接崩溃,却可能悄悄影响业务的正确性或用户体验。比如,调用第三方 API 时返回了空响应、缓存查询未命中、配置文件里某个非关键项缺失
Django怎么防止Celery任务重复执行_Python结合Redis实现分布式锁
Django怎么防止Celery任务重复执行:Python结合Redis实现分布式锁 你遇到过吗?明明只发了一次任务,后台却执行了两次。这不是代码写错了,而是分布式环境下一个经典的老朋友:多个worker同时抢到了同一个活儿。 为什么Celery任务会重复执行 问题的根源在于竞争。想象一下,多个Ce
- 日榜
- 周榜
- 月榜
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
相关攻略
2015-03-10 11:25
2015-03-10 11:05
2021-08-04 13:30
2015-03-10 11:22
2015-03-10 12:39
2022-05-16 18:57
2025-05-23 13:43
2025-05-23 14:01
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程
热门话题

