如何将三参数Action<T,T,T>列表转换为顺序执行的Task列表
改造实现方案
从C# 7.1开始,控制台应用的Main方法原生支持async Task异步入口,不需要额外做阻塞等待即可直接使用async/await语法,完整改造代码如下:
using System; using System.Collections.Generic; using System.Threading.Tasks; class Program { // 原有Action方法定义保持不变即可 static void Action1(string a, string b, string c) => Console.WriteLine($"Action1执行,入参:{a} {b} {c}"); static void Action2(string a, string b, string c) => Console.WriteLine($"Action2执行,入参:{a} {b} {c}"); static void Action3(string a, string b, string c) => Console.WriteLine($"Action3执行,入参:{a} {b} {c}"); static void Action4(string a, string b, string c) => Console.WriteLine($"Action4执行,入参:{a} {b} {c}"); static void Action5(string a, string b, string c) => Console.WriteLine($"Action5执行,入参:{a} {b} {c}"); static async Task Main(string[] args) { var actionList = new List<Action<string, string, string>>() { Action1, Action2, Action3, Action4, Action5 // 可继续追加同签名Action }; foreach (var action in actionList) { // 直接获取当前Action的方法名,和原逻辑完全一致 Console.WriteLine($"Invoking action: {action.Method.Name} ..."); // 顺序执行:await会暂停当前循环,直到当前任务执行完成才会进入下一轮 // 同步Action用Task.Run包装为Task执行,保持异步执行特性 await Task.Run(() => action.Invoke("Hello", "World", "!")); // 原有其他同步逻辑保持不变,会等当前Action执行完成后再运行 Console.WriteLine($"{action.Method.Name} 执行完成"); } } }
核心逻辑说明
- 方法名获取:直接通过委托自带的
Method.Name属性取值,和原同步代码写法完全一致,不需要额外适配 - 顺序执行保证:使用原生
foreach循环+await的组合,每次循环会等待当前Task执行完毕后才会启动下一个任务,完全杜绝并行执行。注意不要使用List<T>.ForEach()方法,它是同步遍历实现,传入异步lambda会生成async void,既无法捕获异常也不能等待执行完成,会出现执行顺序错乱的问题;也不要用Task.WhenAll,该方法会一次性启动所有任务再等待全部完成,不符合顺序执行要求 - 参数一致性:调用Action时传入的三个参数和原代码完全一致,为
"Hello"、"World"、"!",不需要修改参数传递逻辑 - 旧框架兼容:如果使用不支持
async Task Main的旧版.NET Framework,可以把异步执行逻辑抽到单独的async Task方法中,在同步Main里用GetAwaiter().GetResult()等待执行即可,示例代码如下:
// 旧框架兼容写法 static void Main(string[] args) { RunAllActions().GetAwaiter().GetResult(); } static async Task RunAllActions() { // 把前面foreach循环的逻辑放到这里即可 }
- 后续扩展:如果后续需要把列表中的方法替换为异步实现(返回Task的同签名方法),只需要把列表类型从
List<Action<string, string, string>>改为List<Func<string, string, string, Task>>,循环内直接写await action("Hello", "World", "!")即可,其他逻辑不需要改动。
内容的提问来源于stack exchange,提问作者user1855026
相关产品推荐
相关产品推荐

