From afbff7127d9d56fe0f7a35261730e27cf057a6ab Mon Sep 17 00:00:00 2001 From: GeWuYou <95328647+GeWuYou@users.noreply.github.com> Date: Wed, 25 Feb 2026 17:06:03 +0800 Subject: [PATCH] =?UTF-8?q?refactor(extensions):=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E5=BC=82=E6=AD=A5=E6=89=A9=E5=B1=95=E4=B8=AD=E7=9A=84=E8=B6=85?= =?UTF-8?q?=E6=97=B6=E5=A4=84=E7=90=86=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将参数从直接传入Task改为传入接收取消令牌的任务工厂方法 - 更新XML文档注释以反映新的参数设计 - 优化取消令牌处理逻辑,统一管理超时和外部取消信号 - 改进异常处理机制,确保超时情况下正确抛出TimeoutException - 简化代码结构并提高可读性 --- GFramework.Core/extensions/AsyncExtensions.cs | 77 ++++++++++--------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/GFramework.Core/extensions/AsyncExtensions.cs b/GFramework.Core/extensions/AsyncExtensions.cs index edee903..2905b66 100644 --- a/GFramework.Core/extensions/AsyncExtensions.cs +++ b/GFramework.Core/extensions/AsyncExtensions.cs @@ -9,88 +9,91 @@ public static class AsyncExtensions /// 为任务添加超时限制 /// /// 任务结果类型 - /// 要执行的任务 + /// 接收取消令牌并返回任务的工厂方法,令牌将在超时或外部取消时触发 /// 超时时间 - /// 取消令牌 + /// 外部取消令牌 /// 任务结果 - /// 当 task 为 null 时抛出 + /// 当 taskFactory 为 null 时抛出 /// 当任务超时时抛出 /// 当操作被取消时抛出 /// /// - /// var result = await SomeAsyncOperation().WithTimeout(TimeSpan.FromSeconds(5)); + /// var result = await WithTimeout( + /// ct => SomeAsyncOperation(ct), + /// TimeSpan.FromSeconds(5)); /// /// public static async Task WithTimeout( - this Task task, + Func> taskFactory, TimeSpan timeout, CancellationToken cancellationToken = default) { - ArgumentNullException.ThrowIfNull(task); + ArgumentNullException.ThrowIfNull(taskFactory); - using var timeoutCts = new CancellationTokenSource(); - using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCts.Token); + // linkedCts 同时响应:超时 + 外部取消 + using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + linkedCts.CancelAfter(timeout); - var delayTask = Task.Delay(timeout, linkedCts.Token); - var completedTask = await Task.WhenAny(task, delayTask); - - if (completedTask == delayTask) + Task task; + try + { + // 将联合令牌传入实际任务,超时时任务会收到取消信号 + task = taskFactory(linkedCts.Token); + } + catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested) { - cancellationToken.ThrowIfCancellationRequested(); throw new TimeoutException($"操作在 {timeout.TotalSeconds} 秒后超时"); } - await linkedCts.CancelAsync(); try { - await task; + return await task.ConfigureAwait(false); } - catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested && - timeoutCts.Token.IsCancellationRequested) + catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested + && linkedCts.IsCancellationRequested) { - // ignore + // linkedCts 触发但外部未取消 → 超时 + throw new TimeoutException($"操作在 {timeout.TotalSeconds} 秒后超时"); } - - return task.Result; } /// /// 为任务添加超时限制(无返回值版本) /// - /// 要执行的任务 + /// 接收取消令牌并返回任务的工厂方法 /// 超时时间 - /// 取消令牌 - /// 当 task 为 null 时抛出 + /// 外部取消令牌 + /// 当 taskFactory 为 null 时抛出 /// 当任务超时时抛出 /// 当操作被取消时抛出 public static async Task WithTimeout( - this Task task, + Func taskFactory, TimeSpan timeout, CancellationToken cancellationToken = default) { - ArgumentNullException.ThrowIfNull(task); + ArgumentNullException.ThrowIfNull(taskFactory); - using var timeoutCts = new CancellationTokenSource(); - using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCts.Token); + using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + linkedCts.CancelAfter(timeout); - var delayTask = Task.Delay(timeout, linkedCts.Token); - var completedTask = await Task.WhenAny(task, delayTask); - - if (completedTask == delayTask) + Task task; + try + { + task = taskFactory(linkedCts.Token); + } + catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested) { - cancellationToken.ThrowIfCancellationRequested(); throw new TimeoutException($"操作在 {timeout.TotalSeconds} 秒后超时"); } - await linkedCts.CancelAsync(); try { - await task; + await task.ConfigureAwait(false); } - catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested && - timeoutCts.Token.IsCancellationRequested) + catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested + && linkedCts.IsCancellationRequested) { - // ignore + throw new TimeoutException($"操作在 {timeout.TotalSeconds} 秒后超时"); } }