翼度科技»论坛 编程开发 .net 查看内容

.NET 4.0下实现.NET4.5的Task类相似功能组件

11

主题

11

帖子

33

积分

新手上路

Rank: 1

积分
33
实现 .NET 4.0 下的 Task 类相似功能:TaskExCum 组件详解

引言

随着 .NET 技术的发展,异步编程模型逐渐成为现代应用程序开发中的标准实践之一。.NET 4.5 引入了 Task 类,极大地简化了异步编程的过程。然而,许多遗留系统仍在使用 .NET 4.0 或更低版本,这些版本并未直接支持 Task 类的全部功能。为此,我们开发了 TaskExCum 组件,旨在为 .NET 4.0 提供与 .NET 4.5 相似的 Task 功能,包括 Task.Run() 和 Task.WhenAll() 方法。
组件概述

TaskExCum 是一个静态类,提供了以下主要功能:

  • Run 方法:用于异步执行任务,并获取任务的结果。
  • WhenAll 方法:用于等待多个任务完成,并收集所有任务的结果。
实现步骤

接下来,我们将详细讲解 TaskExCum 组件的实现步骤,以便读者能够更好地理解其工作原理,并将其应用于自己的项目中。
步骤 1: 创建 TaskExCum 类

首先,我们需要创建一个静态类 TaskExCum,并在其中定义静态方法。
  1. public static class TaskExCum
  2. {
  3.     // 方法定义将在后续步骤中添加
  4. }
复制代码
步骤 2: 实现 Run 方法

Run 方法允许开发者异步执行任务,并获取任务的结果。我们为 Run 方法提供了两种重载形式,分别用于执行无返回值的操作(Action)和有返回值的操作(Func)。
  1. public static Task<TResult> Run<TResult>(Func<TResult> function)
  2. {
  3. #if NET45
  4.     // 如果目标框架是 .NET 4.5 或更高版本,使用 Task.Run 方法
  5.     return Task.Run(function);
  6. #else
  7.     // 如果目标框架是 .NET 4.0,使用 Task.Factory.StartNew 方法
  8.     return Task.Factory.StartNew(
  9.         function,
  10.         CancellationToken.None,
  11.         TaskCreationOptions.None,
  12.         TaskScheduler.Default
  13.     );
  14. #endif
  15. }
  16. public static Task Run(Action action)
  17. {
  18. #if NET45
  19.     // 如果目标框架是 .NET 4.5 或更高版本,使用 Task.Run 方法
  20.     return Task.Run(action);
  21. #else
  22.     // 如果目标框架是 .NET 4.0,使用 Task.Factory.StartNew 方法
  23.     return Task.Factory.StartNew(
  24.         action,
  25.         CancellationToken.None,
  26.         TaskCreationOptions.None,
  27.         TaskScheduler.Default
  28.     );
  29. #endif
  30. }
复制代码
详细解释

  • 条件编译:使用 #if NET45 编译符号,当项目目标框架为 .NET 4.5 及更高版本时,使用 Task.Run 方法。
  • Task.Factory.StartNew:当项目目标框架为 .NET 4.0 时,使用 Task.Factory.StartNew 方法来启动任务。

    • CancellationToken.None:表示没有取消令牌,任务不会被外部取消。
    • TaskCreationOptions.None:表示没有特殊的任务创建选项。
    • TaskScheduler.Default:这是关键点之一。TaskScheduler.Default 表示使用默认的线程池调度器,这意味着任务会在线程池中的一个线程上执行,而不是每次都启动一个新的线程。这有助于提高性能和资源利用率。

步骤 3: 实现 WhenAll 方法

WhenAll 方法用于等待多个任务完成,并收集所有任务的结果。我们为 WhenAll 方法提供了多种重载形式,以支持不同类型的任务集合。
  1. public static Task<TResult[]> WhenAll<TResult>(IEnumerable<Task<TResult>> tasks)
  2. {
  3. #if NET45
  4.     // 如果目标框架是 .NET 4.5 或更高版本,使用 Task.WhenAll 方法
  5.     return Task.WhenAll(tasks);
  6. #else
  7.     // 如果目标框架是 .NET 4.0,调用 WhenAllCore 方法
  8.     return WhenAllCore(tasks);
  9. #endif
  10. }
  11. public static Task<TResult[]> WhenAll<TResult>(params Task<TResult>[] tasks)
  12. {
  13. #if NET45
  14.     // 如果目标框架是 .NET 4.5 或更高版本,使用 Task.WhenAll 方法
  15.     return Task.WhenAll(tasks);
  16. #else
  17.     // 如果目标框架是 .NET 4.0,调用 WhenAllCore 方法
  18.     return WhenAllCore(tasks);
  19. #endif
  20. }
  21. public static Task WhenAll(IEnumerable<Task> tasks)
  22. {
  23. #if NET45
  24.     // 如果目标框架是 .NET 4.5 或更高版本,使用 Task.WhenAll 方法
  25.     return Task.WhenAll(tasks);
  26. #else
  27.     // 如果目标框架是 .NET 4.0,调用 WhenAllCore 方法
  28.     return WhenAllCore(tasks);
  29. #endif
  30. }
复制代码
详细解释

  • 条件编译:使用 #if NET45 编译符号,当项目目标框架为 .NET 4.5 及更高版本时,使用 Task.WhenAll 方法。
  • WhenAllCore:当项目目标框架为 .NET 4.0 时,调用 WhenAllCore 方法来实现相同的功能。
步骤 4: 实现 WhenAllCore 方法

WhenAllCore 方法是 WhenAll 方法的核心实现,负责处理任务集合,等待所有任务完成,并收集结果或异常信息。
  1. private static Task WhenAllCore(IEnumerable<Task> tasks)
  2. {
  3.     return WhenAllCore(tasks, (completedTasks, tcs) => tcs.TrySetResult(null));
  4. }
  5. private static Task<TResult[]> WhenAllCore<TResult>(IEnumerable<Task<TResult>> tasks)
  6. {
  7.     return WhenAllCore(tasks.Cast<Task>(), (completedTasks, tcs) =>
  8.     {
  9.         tcs.TrySetResult(completedTasks.Select(t => ((Task<TResult>)t).Result).ToArray());
  10.     });
  11. }
  12. private static Task<TResult> WhenAllCore<TResult>(IEnumerable<Task> tasks, Action<Task[], TaskCompletionSource<TResult>> setResultAction)
  13. {
  14.     if (tasks == null)
  15.     {
  16.         throw new ArgumentNullException("tasks");
  17.     }
  18.     Contract.EndContractBlock();
  19.     Contract.Assert(setResultAction != null);
  20.     var tcs = new TaskCompletionSource<TResult>();
  21.     var array = (tasks as Task[]) ?? tasks.ToArray();
  22.     if (array.Length == 0)
  23.     {
  24.         // 如果任务集合为空,直接设置结果
  25.         setResultAction(array, tcs);
  26.     }
  27.     else
  28.     {
  29.         Task.Factory.ContinueWhenAll(array, completedTasks =>
  30.         {
  31.             var exceptions = new List<Exception>();
  32.             bool hasCanceled = false;
  33.             foreach (var task in completedTasks)
  34.             {
  35.                 if (task.IsFaulted)
  36.                 {
  37.                     // 收集所有失败任务的异常信息
  38.                     exceptions.AddRange(task.Exception.InnerExceptions);
  39.                 }
  40.                 else if (task.IsCanceled)
  41.                 {
  42.                     // 检查是否有任务被取消
  43.                     hasCanceled = true;
  44.                 }
  45.             }
  46.             if (exceptions.Count > 0)
  47.             {
  48.                 // 如果有异常,设置异常结果
  49.                 tcs.TrySetException(exceptions);
  50.             }
  51.             else if (hasCanceled)
  52.             {
  53.                 // 如果有任务被取消,设置取消结果
  54.                 tcs.TrySetCanceled();
  55.             }
  56.             else
  57.             {
  58.                 // 如果没有异常且没有任务被取消,设置成功结果
  59.                 setResultAction(completedTasks, tcs);
  60.             }
  61.         }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
  62.     }
  63.     return tcs.Task;
  64. }
复制代码
详细解释

  • 参数验证:检查传入的任务集合是否为 null,如果是,则抛出 ArgumentNullException。
  • TaskCompletionSource:创建一个 TaskCompletionSource 对象,用于管理任务的完成状态。
  • 任务转换:将任务集合转换为数组,以便于后续处理。
  • 任务数量检查:如果任务集合为空,直接调用 setResultAction 设置结果。
  • 等待所有任务完成:使用 Task.Factory.ContinueWhenAll 方法等待所有任务完成。

    • 异常处理:遍历已完成的任务,收集所有失败任务的异常信息。
    • 取消处理:检查是否有任务被取消。
    • 设置结果:如果没有异常且没有任务被取消,调用 setResultAction 设置结果。
    • TaskScheduler.Default:这里再次使用 TaskScheduler.Default,确保任务在默认的线程池中执行,而不是每次都启动新的线程。

步骤 5: 添加异常处理逻辑

为了确保组件的健壮性,我们还需要在 WhenAllCore 方法中添加异常处理逻辑,确保所有异常都能被捕获并正确处理。
  1. private static void AddPotentiallyUnwrappedExceptions(ref List<Exception> targetList, Exception exception)
  2. {
  3.     var ex = exception as AggregateException;
  4.     Contract.Assert(exception != null);
  5.     Contract.Assert(ex == null || ex.InnerExceptions.Count > 0);
  6.     if (targetList == null)
  7.     {
  8.         targetList = new List<Exception>();
  9.     }
  10.     if (ex != null)
  11.     {
  12.         // 如果异常是 AggregateException,添加其内部异常
  13.         targetList.Add(ex.InnerExceptions.Count == 1 ? ex.InnerExceptions[0] : ex);
  14.     }
  15.     else
  16.     {
  17.         // 否则,直接添加异常
  18.         targetList.Add(exception);
  19.     }
  20. }
复制代码
详细解释

  • 异常类型检查:检查传入的异常是否为 AggregateException。
  • 异常列表初始化:如果 targetList 为 null,则初始化一个新的列表。
  • 异常添加:根据异常的类型,将异常或其内部异常添加到列表中。
示例代码

为了帮助读者更好地理解如何使用 TaskExCum 组件,下面是一些示例代码。
示例 1: 使用 Run 方法
  1. using System;
  2. using System.Threading.Tasks;
  3. class Program
  4. {
  5.     static void Main(string[] args)
  6.     {
  7.         try
  8.         {
  9.             // 异步执行任务并等待结果
  10.             string result = TaskExCum.Run(() => "Hello from Task!").Result;
  11.             Console.WriteLine(result);
  12.         }
  13.         catch (Exception ex)
  14.         {
  15.             Console.WriteLine($"Error: {ex.Message}");
  16.         }
  17.     }
  18. }
复制代码
示例 2: 使用 WhenAll 方法
  1. using System;
  2. using System.Linq;
  3. using System.Threading.Tasks;
  4. class Program
  5. {
  6.     static void Main(string[] args)
  7.     {
  8.         try
  9.         {
  10.             // 创建多个任务
  11.             var tasks = Enumerable.Range(1, 5).Select(i => TaskExCum.Run(() => i * i)).ToArray();
  12.             
  13.             // 等待所有任务完成并获取结果
  14.             int[] results = TaskExCum.WhenAll(tasks).Result;
  15.             
  16.             // 输出结果
  17.             foreach (var result in results)
  18.             {
  19.                 Console.WriteLine(result);
  20.             }
  21.         }
  22.         catch (Exception ex)
  23.         {
  24.             Console.WriteLine($"Error: {ex.Message}");
  25.         }
  26.     }
  27. }
复制代码
结论

通过 TaskExCum 组件,即使是在 .NET 4.0 这样的老框架版本中,我们也能够享受到现代异步编程模型带来的便利。希望这个组件能够帮助那些需要在旧版 .NET 框架中实现异步操作的开发者们,提高他们的开发效率和代码质量。如果你有任何建议或改进意见,欢迎留言交流!
详情请看:https://www.cnblogs.com/Bob-luo/p/18515670
以上就是关于 TaskExCum 组件的详细介绍。希望通过这篇文章,读者能够更好地理解和使用这个组件,从而在自己的项目中实现高效的异步编程。如果有任何问题或需要进一步的帮助,请随时留言!

来源:https://www.cnblogs.com/Bob-luo/p/18515670
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具