using GFramework.Core.Functional; namespace GFramework.Core.extensions; /// /// 异步扩展方法 /// public static class AsyncExtensions { /// /// 为任务添加超时限制 /// /// 任务结果类型 /// 接收取消令牌并返回任务的工厂方法,令牌将在超时或外部取消时触发 /// 超时时间 /// 外部取消令牌 /// 任务结果 /// 当 taskFactory 为 null 时抛出 /// 当任务超时时抛出 /// 当操作被取消时抛出 /// /// /// var result = await WithTimeout( /// ct => SomeAsyncOperation(ct), /// TimeSpan.FromSeconds(5)); /// /// public static async Task WithTimeout( Func> taskFactory, TimeSpan timeout, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(taskFactory); // linkedCts 同时响应:超时 + 外部取消 using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); linkedCts.CancelAfter(timeout); Task task; try { // 将联合令牌传入实际任务,超时时任务会收到取消信号 task = taskFactory(linkedCts.Token); } catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested) { throw new TimeoutException($"操作在 {timeout.TotalSeconds} 秒后超时"); } try { return await task.ConfigureAwait(false); } catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested && linkedCts.IsCancellationRequested) { // linkedCts 触发但外部未取消 → 超时 throw new TimeoutException($"操作在 {timeout.TotalSeconds} 秒后超时"); } } /// /// 为任务添加超时限制(无返回值版本) /// /// 接收取消令牌并返回任务的工厂方法 /// 超时时间 /// 外部取消令牌 /// 当 taskFactory 为 null 时抛出 /// 当任务超时时抛出 /// 当操作被取消时抛出 public static async Task WithTimeout( Func taskFactory, TimeSpan timeout, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(taskFactory); using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); linkedCts.CancelAfter(timeout); Task task; try { task = taskFactory(linkedCts.Token); } catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested) { throw new TimeoutException($"操作在 {timeout.TotalSeconds} 秒后超时"); } try { await task.ConfigureAwait(false); } catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested && linkedCts.IsCancellationRequested) { throw new TimeoutException($"操作在 {timeout.TotalSeconds} 秒后超时"); } } /// /// 为任务工厂添加重试机制 /// /// 任务结果类型 /// 任务工厂函数 /// 最大重试次数 /// 重试间隔 /// 判断是否应该重试的函数,默认对所有异常重试 /// 当为 true 时直接抛出原始异常,否则包装为 AggregateException /// 任务结果 /// 当 taskFactory 为 null 时抛出 /// 当 maxRetries 小于 0 时抛出 /// /// /// var result = await (() => UnreliableOperation()) /// .WithRetry(maxRetries: 3, delay: TimeSpan.FromSeconds(1)); /// /// public static async Task WithRetry( this Func> taskFactory, int maxRetries, TimeSpan delay, Func? shouldRetry = null, bool throwOriginal = false) { ArgumentNullException.ThrowIfNull(taskFactory); if (maxRetries < 0) throw new ArgumentOutOfRangeException(nameof(maxRetries), "最大重试次数不能为负数"); shouldRetry ??= _ => true; for (var attempt = 0; attempt <= maxRetries; attempt++) { try { return await taskFactory(); } catch (Exception ex) { // 若还有重试机会且允许重试,则等待后继续;否则统一包装为 AggregateException 抛出 if (attempt < maxRetries && shouldRetry(ex)) { await Task.Delay(delay); } else { if (throwOriginal) throw; throw new AggregateException($"操作在 {attempt} 次重试后仍然失败", ex); } } } // 理论上不可达,仅满足编译器要求 throw new AggregateException($"操作在 {maxRetries} 次重试后仍然失败"); } /// /// 安全执行异步操作,将异常包装为 Result 类型 /// /// 任务结果类型 /// 要执行的异步函数 /// 包含结果或异常的 Result 对象 /// 当 func 为 null 时抛出 /// /// /// var result = await (() => RiskyOperation()).TryAsync(); /// result.Match( /// value => Console.WriteLine($"成功: {value}"), /// error => Console.WriteLine($"失败: {error.Message}") /// ); /// /// public static async Task> TryAsync(this Func> func) { ArgumentNullException.ThrowIfNull(func); try { var result = await func(); return new Result(result); } catch (Exception ex) { return new Result(ex); } } /// /// 等待所有任务完成 /// /// 任务集合 /// 当 tasks 为 null 时抛出 /// /// /// var tasks = new[] { Task1(), Task2(), Task3() }; /// await tasks.WhenAll(); /// /// public static Task WhenAll(this IEnumerable tasks) { ArgumentNullException.ThrowIfNull(tasks); return Task.WhenAll(tasks); } /// /// 等待所有任务完成并返回结果数组 /// /// 任务结果类型 /// 任务集合 /// 所有任务的结果数组 /// 当 tasks 为 null 时抛出 /// /// /// var tasks = new[] { GetValue1(), GetValue2(), GetValue3() }; /// var results = await tasks.WhenAll(); /// /// public static Task WhenAll(this IEnumerable> tasks) { ArgumentNullException.ThrowIfNull(tasks); return Task.WhenAll(tasks); } /// /// 为任务添加失败回退机制 /// /// 任务结果类型 /// 要执行的任务 /// 失败时的回退函数 /// 任务结果或回退值 /// 当 task 或 fallback 为 null 时抛出 /// /// /// var result = await RiskyOperation() /// .WithFallback(ex => DefaultValue); /// /// public static async Task WithFallback(this Task task, Func fallback) { ArgumentNullException.ThrowIfNull(task); ArgumentNullException.ThrowIfNull(fallback); try { return await task; } catch (Exception ex) { return fallback(ex); } } }