using System; using System.Threading; using System.Threading.Tasks; namespace MainShell.Common { public class RetryMechanism { // 自定义异常:操作失败 public class RetryException : Exception { public RetryException(string message) : base(message) { } } public class RetryResult { public bool Succeeded { get; set; } public bool IsAborted { get; set; } public int AttemptCount { get; set; } public int MaxAttempts { get; set; } public string Message { get; set; } } /// /// 向后兼容旧接口:默认直接继续重试直到达到最大次数,失败时抛异常。 /// 新代码建议优先使用 或返回结果对象的重载。 /// public static void RetryIfNeeded(Func checkCondition, string message, int maxAttempts = 3) { RetryOrThrow(checkCondition, attempt => true, message, maxAttempts); } /// /// 执行同步重试并返回结果对象。 /// /// /// 每次尝试时执行的检查逻辑。 /// 返回 true 表示成功,返回 false 表示本次失败并根据 决定是否继续。 /// 如果该委托抛出异常,则异常会直接向外传播,不会被当前重试机制捕获或吞掉,也不会自动进入下一次重试。 /// /// 当一次尝试失败后,决定是否继续重试。参数为当前已完成的尝试次数,从 1 开始计数。 /// 操作描述信息。 /// 最大尝试次数,必须大于 0。 public static RetryResult RetryIfNeeded(Func checkCondition, Func shouldRetry, string message, int maxAttempts = 3) { if (checkCondition == null) { throw new ArgumentNullException(nameof(checkCondition)); } if (shouldRetry == null) { throw new ArgumentNullException(nameof(shouldRetry)); } if (maxAttempts <= 0) { throw new ArgumentOutOfRangeException(nameof(maxAttempts), "maxAttempts must be greater than 0."); } for (int attempt = 1; attempt <= maxAttempts; attempt++) { bool conditionMet = checkCondition(); if (conditionMet) { return new RetryResult { Succeeded = true, AttemptCount = attempt, MaxAttempts = maxAttempts, Message = message }; } if (attempt == maxAttempts) { return new RetryResult { Succeeded = false, AttemptCount = attempt, MaxAttempts = maxAttempts, Message = message }; } bool continueRetry = shouldRetry(attempt); if (!continueRetry) { return new RetryResult { Succeeded = false, IsAborted = true, AttemptCount = attempt, MaxAttempts = maxAttempts, Message = message }; } } return new RetryResult { Succeeded = false, AttemptCount = maxAttempts, MaxAttempts = maxAttempts, Message = message }; } // 保留抛异常风格的兼容方法 public static void RetryOrThrow(Func checkCondition, Func shouldRetry, string message, int maxAttempts = 3) { var result = RetryIfNeeded(checkCondition, shouldRetry, message, maxAttempts); EnsureSuccess(result); } /// /// 向后兼容旧接口的异步版本:默认直接继续重试直到达到最大次数,失败时抛异常。 /// 新代码建议优先使用 或返回结果对象的重载。 /// public static async Task RetryIfNeededAsync(Func> checkConditionAsync, string message, int maxAttempts = 3) { await RetryOrThrowAsync(checkConditionAsync, attempt => Task.FromResult(true), message, maxAttempts, CancellationToken.None).ConfigureAwait(false); } /// /// 执行异步重试并返回结果对象。 /// /// /// 每次尝试时执行的异步检查逻辑。 /// 返回 true 表示成功,返回 false 表示本次失败并根据 决定是否继续。 /// 如果该委托抛出异常,则异常会直接向外传播,不会被当前重试机制捕获或吞掉,也不会自动进入下一次重试。 /// /// 当一次尝试失败后,决定是否继续重试。参数为当前已完成的尝试次数,从 1 开始计数。 /// 操作描述信息。 /// 最大尝试次数,必须大于 0。 /// 用于取消异步重试流程。 public static async Task RetryIfNeededAsync(Func> checkConditionAsync, Func> shouldRetryAsync, string message, int maxAttempts = 3, CancellationToken cancellationToken = default(CancellationToken)) { if (checkConditionAsync == null) { throw new ArgumentNullException(nameof(checkConditionAsync)); } if (shouldRetryAsync == null) { throw new ArgumentNullException(nameof(shouldRetryAsync)); } if (maxAttempts <= 0) { throw new ArgumentOutOfRangeException(nameof(maxAttempts), "maxAttempts must be greater than 0."); } for (int attempt = 1; attempt <= maxAttempts; attempt++) { cancellationToken.ThrowIfCancellationRequested(); bool conditionMet = await checkConditionAsync().ConfigureAwait(false); if (conditionMet) { return new RetryResult { Succeeded = true, AttemptCount = attempt, MaxAttempts = maxAttempts, Message = message }; } if (attempt == maxAttempts) { return new RetryResult { Succeeded = false, AttemptCount = attempt, MaxAttempts = maxAttempts, Message = message }; } cancellationToken.ThrowIfCancellationRequested(); bool continueRetry = await shouldRetryAsync(attempt).ConfigureAwait(false); if (!continueRetry) { return new RetryResult { Succeeded = false, IsAborted = true, AttemptCount = attempt, MaxAttempts = maxAttempts, Message = message }; } } return new RetryResult { Succeeded = false, AttemptCount = maxAttempts, MaxAttempts = maxAttempts, Message = message }; } // 保留抛异常风格的异步兼容方法 public static async Task RetryOrThrowAsync(Func> checkConditionAsync, Func> shouldRetryAsync, string message, int maxAttempts = 3, CancellationToken cancellationToken = default(CancellationToken)) { var result = await RetryIfNeededAsync(checkConditionAsync, shouldRetryAsync, message, maxAttempts, cancellationToken).ConfigureAwait(false); EnsureSuccess(result); } private static void EnsureSuccess(RetryResult result) { if (result.Succeeded) { return; } if (result.IsAborted) { throw new RetryException($"{result.Message} 已中止重试,操作失败。尝试次数: {result.AttemptCount}/{result.MaxAttempts}"); } throw new RetryException($"{result.Message} 已达到最大重试次数,操作失败。尝试次数: {result.AttemptCount}/{result.MaxAttempts}"); } } }