最干净的方式来编写重试逻辑?

偶尔我需要在放弃之前多次重试一次手术。 我的代码是这样的:

int retries = 3; while(true) { try { DoSomething(); break; // success! } catch { if(--retries == 0) throw; else Thread.Sleep(1000); } } 

我想重写这一般的重试function,如:

 TryThreeTimes(DoSomething); 

在C#中可能吗? TryThreeTimes()方法的代码是什么?

如果用作通用的exception处理机制,那么只需重试相同的调用就可能是危险的。 话虽如此,这里是一个基于lambda的重试包装,你可以使用任何方法。 我select将重试次数和重试超时时间作为参数进行比较,以获得更多的灵活性:

 public static class Retry { public static void Do( Action action, TimeSpan retryInterval, int maxAttemptCount = 3) { Do<object>(() => { action(); return null; }, retryInterval, maxAttemptCount); } public static T Do<T>( Func<T> action, TimeSpan retryInterval, int maxAttemptCount = 3) { var exceptions = new List<Exception>(); for (int attempted = 0; attempted < maxAttemptCount; attempted++) { try { if (attempted > 0) { Thread.Sleep(retryInterval); } return action(); } catch (Exception ex) { exceptions.Add(ex); } } throw new AggregateException(exceptions); } } 

您现在可以使用此实用程序方法来执行重试逻辑:

 Retry.Do(() => SomeFunctionThatCanFail(), TimeSpan.FromSeconds(1)); 

要么:

 Retry.Do(SomeFunctionThatCanFail, TimeSpan.FromSeconds(1)); 

要么:

 int result = Retry.Do(SomeFunctionWhichReturnsInt, TimeSpan.FromSeconds(1), 4); 

或者你甚至可以做一个async超载。

你应该试试波莉 。 这是一个由我编写的.NET库,它允许开发人员以stream畅的方式expression暂时的exception处理策略,例如重试,重试永久,等待和重试或断路器。

 Policy .Handle<SqlException>(ex => ex.Number == 1205) .Or<ArgumentException>(ex => ex.ParamName == "example") .WaitAndRetry(3, retryAttempt => TimeSpan.FromSeconds(3)) .Execute(() => DoSomething()); 

这可能是一个坏主意。 首先,它是“疯狂的定义两次做同样的事情,每次都期待着不同的结果”这个格言的象征。 其次,这种编码模式与自身并不完美。 例如:

假设您的networking硬件层在发生故障时重新发送一个数据包三次,比如等待一秒之间。

现在假设软件层在数据包失败时重新发送三次关于失败的通知。

现在假设通知层在通知传递失败时重新激活通知三次。

现在假设错误报告层在通知失败时重新激活通知层三次。

现在假设Web服务器在错误失败时重新激活错误报告三次。

现在假设Web客户端在从服务器获取错误时重新发送请求三次。

现在假设networking交换机上应该将通知路由到pipe理员的线路被拔出。 什么时候Web客户端的用户最终得到错误信息? 大约十二分钟后我做了。

免得你认为这只是一个愚蠢的例子:我们已经看到客户代码中的这个错误,尽pipe远远比我在这里描述的更糟。 在特定的客户代码中,发生错误的情况与最终报告给用户之间的差距是几个星期,因为如此多的层自动重试等待。 试想一下,如果有十次而不是三次 ,会发生什么。

通常,对错误情况正确的做法是立即报告,并让用户决定要做什么。 如果用户想要创build一个自动重试的策略,让他们在软件抽象的适当级别创build该策略。

 public void TryThreeTimes(Action action) { var tries = 3; while (true) { try { action(); break; // success! } catch { if (--tries == 0) throw; Thread.Sleep(1000); } } } 

那么你会打电话给:

 TryThreeTimes(DoSomething); 

…或者…

 TryThreeTimes(() => DoSomethingElse(withLocalVariable)); 

更灵活的select:

 public void DoWithRetry(Action action, TimeSpan sleepPeriod, int tryCount = 3) { if (tryCount <= 0) throw new ArgumentOutOfRangeException(nameof(tryCount)); while (true) { try { action(); break; // success! } catch { if (--tryCount == 0) throw; Thread.Sleep(sleepPeriod); } } } 

用作:

 DoWithRetry(DoSomething, TimeSpan.FromSeconds(2), tryCount: 10); 

支持asynchronous/等待的更现代的版本:

 public async Task DoWithRetryAsync(Func<Task> action, TimeSpan sleepPeriod, int tryCount = 3) { if (tryCount <= 0) throw new ArgumentOutOfRangeException(nameof(tryCount)); while (true) { try { await action(); return; // success! } catch { if (--tryCount == 0) throw; await Task.Delay(sleepPeriod); } } } 

用作:

 await DoWithRetryAsync(DoSomethingAsync, TimeSpan.FromSeconds(2), tryCount: 10); 

瞬态故障处理应用程序块提供了一个可扩展的重试策略集合,包括:

  • 增加的
  • 固定间隔
  • 指数后退

它还包括一系列基于云的服务的错误检测策略。

有关更多信息,请参阅开发人员指南的这一章 。

可通过NuGet (search“ 黄玉 ”)。

允许function并重试消息

 public static T RetryMethod<T>(Func<T> method, int numRetries, int retryTimeout, Action onFailureAction) { Guard.IsNotNull(method, "method"); T retval = default(T); do { try { retval = method(); return retval; } catch { onFailureAction(); if (numRetries <= 0) throw; // improved to avoid silent failure Thread.Sleep(retryTimeout); } } while (numRetries-- > 0); return retval; } 

您也可以考虑添加要重试的exceptiontypes。 例如,这是一个超时exception,你想重试? 数据库exception?

 RetryForExcpetionType(DoSomething, typeof(TimeoutException), 5, 1000); public static void RetryForExcpetionType(Action action, Type retryOnExceptionType, int numRetries, int retryTimeout) { if (action == null) throw new ArgumentNullException("action"); if (retryOnExceptionType == null) throw new ArgumentNullException("retryOnExceptionType"); while (true) { try { action(); return; } catch(Exception e) { if (--numRetries <= 0 || !retryOnExceptionType.IsAssignableFrom(e.GetType())) throw; if (retryTimeout > 0) System.Threading.Thread.Sleep(retryTimeout); } } } 

您可能还会注意到,所有其他示例与重试== 0的testing都有类似的问题,要么重试无穷大,要么在给定负值时无法引发exception。 另外睡眠(-1000)将在上面的catch块失败。 取决于你期望人们如何“愚蠢”,但防御性的编程永远不会受到伤害。

我是recursion和扩展方法的粉丝,所以这里是我的两分钱:

 public static void InvokeWithRetries(this Action @this, ushort numberOfRetries) { try { @this(); } catch { if (numberOfRetries == 0) throw; InvokeWithRetries(@this, --numberOfRetries); } } 

在前面的工作的基础上,我想通过三种方式来增强重试逻辑:

  1. 指定要捕获/重试的exceptiontypes。 这是主要的增强,因为任何exception重试都是错误的。
  2. 不要在try / catch中嵌套最后一个尝试,取得稍好的性能
  3. 使其成为一个Action扩展方法

     static class ActionExtensions { public static void InvokeAndRetryOnException<T> (this Action action, int retries, TimeSpan retryDelay) where T : Exception { if (action == null) throw new ArgumentNullException("action"); while( retries-- > 0 ) { try { action( ); return; } catch (T) { Thread.Sleep( retryDelay ); } } action( ); } } 

然后可以像这样调用该方法(当然也可以使用匿名方法):

 new Action( AMethodThatMightThrowIntermittentException ) .InvokeAndRetryOnException<IntermittentException>( 2, TimeSpan.FromSeconds( 1 ) ); 

我会实现这个:

 public static bool Retry(int maxRetries, Func<bool, bool> method) { while (maxRetries > 0) { if (method(maxRetries == 1)) { return true; } maxRetries--; } return false; } 

我不会像在其他例子中那样使用exception。 在我看来,如果我们期待一种方法不能成功的可能性,那么它的失败并不是一个例外。 所以我调用的方法如果成功则返回true,否则返回false。

为什么它是一个Func<bool, bool>而不仅仅是一个Func<bool> ? 所以,如果我想要一个方法能够抛出一个exception的失败,我有一种方式告诉它,这是最后的尝试。

所以我可以使用代码如下:

 Retry(5, delegate(bool lastIteration) { // do stuff if (!succeeded && lastIteration) { throw new InvalidOperationException(...) } return succeeded; }); 

要么

 if (!Retry(5, delegate(bool lastIteration) { // do stuff return succeeded; })) { Console.WriteLine("Well, that didn't work."); } 

如果传递一个方法没有使用的参数certificate是非常笨拙的,那么实现一个只需要一个Func<bool>Retry重载也是微不足道的。

使用波莉

https://github.com/App-vNext/Polly-Samples

这里是一个重试通用我用波利

 public T Retry<T>(Func<T> action, int retryCount = 0) { PolicyResult<T> policyResult = Policy .Handle<Exception>() .Retry(retryCount) .ExecuteAndCapture<T>(action); if (policyResult.Outcome == OutcomeType.Failure) { throw policyResult.FinalException; } return policyResult.Result; } 

像这样使用它

 var result = Retry(() => MyFunction()), 3); 

用C#6.0保持简单

 public async Task<T> Retry<T>(Func<T> action, TimeSpan retryInterval, int retryCount) { try { return action(); } catch when (retryCount != 0) { await Task.Delay(retryInterval); return await Retry(action, retryInterval, --retryCount); } } 

对于那些想要同时对任何exception重试的选项或显式设置exceptiontypes的用户,请使用以下命令:

 public class RetryManager { public void Do(Action action, TimeSpan interval, int retries = 3) { Try<object, Exception>(() => { action(); return null; }, interval, retries); } public T Do<T>(Func<T> action, TimeSpan interval, int retries = 3) { return Try<T, Exception>( action , interval , retries); } public T Do<E, T>(Func<T> action, TimeSpan interval, int retries = 3) where E : Exception { return Try<T, E>( action , interval , retries); } public void Do<E>(Action action, TimeSpan interval, int retries = 3) where E : Exception { Try<object, E>(() => { action(); return null; }, interval, retries); } private T Try<T, E>(Func<T> action, TimeSpan interval, int retries = 3) where E : Exception { var exceptions = new List<E>(); for (int retry = 0; retry < retries; retry++) { try { if (retry > 0) Thread.Sleep(interval); return action(); } catch (E ex) { exceptions.Add(ex); } } throw new AggregateException(exceptions); } } 

我需要一个支持取消的方法,而我在这个方面,我增加了对返回中间错误的支持。

 public static class ThreadUtils { public static RetryResult Retry( Action target, CancellationToken cancellationToken, int timeout = 5000, int retries = 0) { CheckRetryParameters(timeout, retries) var failures = new List<Exception>(); while(!cancellationToken.IsCancellationRequested) { try { target(); return new RetryResult(failures); } catch (Exception ex) { failures.Add(ex); } if (retries > 0) { retries--; if (retries == 0) { throw new AggregateException( "Retry limit reached, see InnerExceptions for details.", failures); } } if (cancellationToken.WaitHandle.WaitOne(timeout)) { break; } } failures.Add(new OperationCancelledException( "The Retry Operation was cancelled.")); throw new AggregateException("Retry was cancelled.", failures); } private static void CheckRetryParameters(int timeout, int retries) { if (timeout < 1) { throw new ArgumentOutOfRangeException(... } if (retries < 0) { throw new ArgumentOutOfRangeException(... } } public class RetryResult : IEnumerable<Exception> { private readonly IEnumerable<Exception> failureExceptions; private readonly int failureCount; protected internal RetryResult( ICollection<Exception> failureExceptions) { this.failureExceptions = failureExceptions; this.failureCount = failureExceptions.Count; } } public int FailureCount { get { returm this.failureCount; } } public IEnumerator<Exception> GetEnumerator() { return this.failureExceptions.GetEnumerator(); } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return this.GetEnumerator(); } } 

您可以像这样使用Retryfunction,以10秒的延迟重试3次,但不会取消。

 try { var result = ThreadUtils.Retry( SomeAction, CancellationToken.None, 10000, 3); // it worked result.FailureCount // but failed this many times first. } catch (AggregationException ex) { // oops, 3 retries wasn't enough. } 

或者每五秒钟重新尝试一次,除非取消。

 try { var result = ThreadUtils.Retry( SomeAction, someTokenSource.Token); // it worked result.FailureCount // but failed this many times first. } catch (AggregationException ex) { // operation was cancelled before success. } 

正如你所猜,在我的源代码中,我已经重载了Retry函数来支持我想要使用的不同的types。

我的async实现的重试方法:

 public static async Task<T> DoAsync<T>(Func<dynamic> action, TimeSpan retryInterval, int retryCount = 3) { var exceptions = new List<Exception>(); for (int retry = 0; retry < retryCount; retry++) { try { return await action().ConfigureAwait(false); } catch (Exception ex) { exceptions.Add(ex); } await Task.Delay(retryInterval).ConfigureAwait(false); } throw new AggregateException(exceptions); } 

要点:我用.ConfigureAwait(false);Func<dynamic>而不是Func<T>

或者如何做一点整洁….

 int retries = 3; while (retries > 0) { if (DoSomething()) { retries = 0; } else { retries--; } } 

我相信抛出exception通常应该作为一种机制来避免,除非你把它们在边界之间传递(比如build立一个其他人可以使用的库)。 为什么不只是DoSomething()命令返回true ,否则返回false

编辑:这可以被封装在一个像其他人所build议的function。 唯一的问题是如果你不是自己编写DoSomething()函数

我需要传递一些参数给我的方法重试,并有一个结果值; 所以我需要一个expression式..我build立这个类的工作(这是灵感的LBushkin的),你可以这样使用它:

 static void Main(string[] args) { // one shot var res = Retry<string>.Do(() => retryThis("try"), 4, TimeSpan.FromSeconds(2), fix); // delayed execute var retry = new Retry<string>(() => retryThis("try"), 4, TimeSpan.FromSeconds(2), fix); var res2 = retry.Execute(); } static void fix() { Console.WriteLine("oh, no! Fix and retry!!!"); } static string retryThis(string tryThis) { Console.WriteLine("Let's try!!!"); throw new Exception(tryThis); } public class Retry<TResult> { Expression<Func<TResult>> _Method; int _NumRetries; TimeSpan _RetryTimeout; Action _OnFailureAction; public Retry(Expression<Func<TResult>> method, int numRetries, TimeSpan retryTimeout, Action onFailureAction) { _Method = method; _NumRetries = numRetries; _OnFailureAction = onFailureAction; _RetryTimeout = retryTimeout; } public TResult Execute() { TResult result = default(TResult); while (_NumRetries > 0) { try { result = _Method.Compile()(); break; } catch { _OnFailureAction(); _NumRetries--; if (_NumRetries <= 0) throw; // improved to avoid silent failure Thread.Sleep(_RetryTimeout); } } return result; } public static TResult Do(Expression<Func<TResult>> method, int numRetries, TimeSpan retryTimeout, Action onFailureAction) { var retry = new Retry<TResult>(method, numRetries, retryTimeout, onFailureAction); return retry.Execute(); } } 

PS。 LBushkin的解决scheme再做一个重试= D

我会将下面的代码添加到接受的答案

 public static class Retry<TException> where TException : Exception //ability to pass the exception type { //same code as the accepted answer .... public static T Do<T>(Func<T> action, TimeSpan retryInterval, int retryCount = 3) { var exceptions = new List<Exception>(); for (int retry = 0; retry < retryCount; retry++) { try { return action(); } catch (TException ex) //Usage of the exception type { exceptions.Add(ex); Thread.Sleep(retryInterval); } } throw new AggregateException(String.Format("Failed to excecute after {0} attempt(s)", retryCount), exceptions); } } 

基本上上面的代码使得Retry类是通用的,所以你可以传递你想要捕获的exception的types来重试。

现在几乎以相同的方式使用它,但指定exceptiontypes

 Retry<EndpointNotFoundException>.Do(() => SomeFunctionThatCanFail(), TimeSpan.FromSeconds(1)); 

我知道这个答案是非常古老的,但我只是想对此发表评论,因为我已经遇到了使用这些问题的时间,不pipe用计数器的任何陈述。

多年来,我已经解决了一个更好的方法,我认为。 那就是使用某种事件集合,比如被动扩展“Subject”等。 尝试失败时,只需发布​​说明尝试失败的事件,然后让聚合器function重新安排事件。 这允许你更多地控制重试,而不用一堆重试循环来污染呼叫本身,而不是重复循环。 你也没有捆绑一个线程睡觉一个单一的线程。

在C#,Java或其他语言中简单操作:

  internal class ShouldRetryHandler { private static int RETRIES_MAX_NUMBER = 3; private static int numberTryes; public static bool shouldRetry() { var statusRetry = false; if (numberTryes< RETRIES_MAX_NUMBER) { numberTryes++; statusRetry = true; //log msg -> 'retry number' + numberTryes } else { statusRetry = false; //log msg -> 'reached retry number limit' } return statusRetry; } } 

并在你的代码中使用它非常简单:

  void simpleMethod(){ //some code if(ShouldRetryHandler.shouldRetry()){ //do some repetitive work } //some code } 

或者你可以在recursion方法中使用它:

 void recursiveMethod(){ //some code if(ShouldRetryHandler.shouldRetry()){ recursiveMethod(); } //some code } 
 int retries = 3; while (true) { try { //Do Somthing break; } catch (Exception ex) { if (--retries == 0) return Request.BadRequest(ApiUtil.GenerateRequestResponse(false, "3 Times tried it failed do to : " + ex.Message, new JObject())); else System.Threading.Thread.Sleep(100); } 

指数退避是一个很好的重试策略,而不仅仅是尝试x次。 你可以使用像波利这样的库来实现它。

 public delegate void ThingToTryDeletage(); public static void TryNTimes(ThingToTryDelegate, int N, int sleepTime) { while(true) { try { ThingToTryDelegate(); } catch { if( --N == 0) throw; else Thread.Sleep(time); } } 

我根据这里发布的答案写了一个小class。 希望它会帮助某人: https : //github.com/natenho/resiliency

 using System; using System.Threading; /// <summary> /// Classe utilitária para suporte a resiliência /// </summary> public sealed class Resiliency { /// <summary> /// Define o valor padrão de número de tentativas /// </summary> public static int DefaultRetryCount { get; set; } /// <summary> /// Define o valor padrão (em segundos) de tempo de espera entre tentativas /// </summary> public static int DefaultRetryTimeout { get; set; } /// <summary> /// Inicia a parte estática da resiliência, com os valores padrões /// </summary> static Resiliency() { DefaultRetryCount = 3; DefaultRetryTimeout = 0; } /// <summary> /// Executa uma <see cref="Action"/> e tenta novamente DefaultRetryCount vezes quando for disparada qualquer <see cref="Exception"/> /// </summary> /// <param name="action">Ação a ser realizada</param> /// <remarks>Executa uma vez e realiza outras DefaultRetryCount tentativas em caso de exceção. Não aguarda para realizar novas tentativa.</remarks> public static void Try(Action action) { Try<Exception>(action, DefaultRetryCount, TimeSpan.FromMilliseconds(DefaultRetryTimeout), null); } /// <summary> /// Executa uma <see cref="Action"/> e tenta novamente determinado número de vezes quando for disparada qualquer <see cref="Exception"/> /// </summary> /// <param name="action">Ação a ser realizada</param> /// <param name="retryCount">Número de novas tentativas a serem realizadas</param> /// <param name="retryTimeout">Tempo de espera antes de cada nova tentativa</param> public static void Try(Action action, int retryCount, TimeSpan retryTimeout) { Try<Exception>(action, retryCount, retryTimeout, null); } /// <summary> /// Executa uma <see cref="Action"/> e tenta novamente determinado número de vezes quando for disparada qualquer <see cref="Exception"/> /// </summary> /// <param name="action">Ação a ser realizada</param> /// <param name="retryCount">Número de novas tentativas a serem realizadas</param> /// <param name="retryTimeout">Tempo de espera antes de cada nova tentativa</param> /// <param name="tryHandler">Permitindo manipular os critérios para realizar as tentativas</param> public static void Try(Action action, int retryCount, TimeSpan retryTimeout, Action<ResiliencyTryHandler<Exception>> tryHandler) { Try<Exception>(action, retryCount, retryTimeout, tryHandler); } /// <summary> /// Executa uma <see cref="Action"/> e tenta novamente por até DefaultRetryCount vezes quando for disparada qualquer <see cref="Exception"/> /// </summary> /// <param name="action">Ação a ser realizada</param> /// <param name="tryHandler">Permitindo manipular os critérios para realizar as tentativas</param> /// <remarks>Executa uma vez e realiza outras DefaultRetryCount tentativas em caso de exceção. Aguarda DefaultRetryTimeout segundos antes de realizar nova tentativa.</remarks> public static void Try(Action action, Action<ResiliencyTryHandler<Exception>> tryHandler) { Try<Exception>(action, DefaultRetryCount, TimeSpan.FromSeconds(DefaultRetryTimeout), null); } /// <summary> /// Executa uma <see cref="Action"/> e tenta novamente determinado número de vezes quando for disparada qualquer <see cref="TException"/> /// </summary> /// <param name="action">Ação a ser realizada</param> /// <remarks>Executa uma vez e realiza outras DefaultRetryCount tentativas em caso de exceção. Aguarda DefaultRetryTimeout segundos antes de realizar nova tentativa.</remarks> public static void Try<TException>(Action action) where TException : Exception { Try<TException>(action, DefaultRetryCount, TimeSpan.FromSeconds(DefaultRetryTimeout), null); } /// <summary> /// Executa uma <see cref="Action"/> e tenta novamente determinado número de vezes quando for disparada qualquer <see cref="TException"/> /// </summary> /// <param name="action">Ação a ser realizada</param> /// <param name="retryCount"></param> public static void Try<TException>(Action action, int retryCount) where TException : Exception { Try<TException>(action, retryCount, TimeSpan.FromSeconds(DefaultRetryTimeout), null); } /// <summary> /// Executa uma <see cref="Action"/> e tenta novamente determinado número de vezes quando for disparada qualquer <see cref="Exception"/> /// </summary> /// <param name="action">Ação a ser realizada</param> /// <param name="retryCount"></param> /// <param name="retryTimeout"></param> public static void Try<TException>(Action action, int retryCount, TimeSpan retryTimeout) where TException : Exception { Try<TException>(action, retryCount, retryTimeout, null); } /// <summary> /// Executa uma <see cref="Action"/> e tenta novamente determinado número de vezes quando for disparada qualquer <see cref="Exception"/> /// </summary> /// <param name="action">Ação a ser realizada</param> /// <param name="tryHandler">Permitindo manipular os critérios para realizar as tentativas</param> /// <remarks>Executa uma vez e realiza outras DefaultRetryCount tentativas em caso de exceção. Aguarda DefaultRetryTimeout segundos antes de realizar nova tentativa.</remarks> public static void Try<TException>(Action action, Action<ResiliencyTryHandler<TException>> tryHandler) where TException : Exception { Try(action, DefaultRetryCount, TimeSpan.FromSeconds(DefaultRetryTimeout), tryHandler); } /// <summary> /// Executa uma <see cref="Action"/> e tenta novamente determinado número de vezes quando for disparada uma <see cref="Exception"/> definida no tipo genérico /// </summary> /// <param name="action">Ação a ser realizada</param> /// <param name="retryCount">Número de novas tentativas a serem realizadas</param> /// <param name="retryTimeout">Tempo de espera antes de cada nova tentativa</param> /// <param name="tryHandler">Permitindo manipular os critérios para realizar as tentativas</param> /// <remarks>Construído a partir de várias ideias no post <seealso cref="http://stackoverflow.com/questions/156DefaultRetryCount191/c-sharp-cleanest-way-to-write-retry-logic"/></remarks> public static void Try<TException>(Action action, int retryCount, TimeSpan retryTimeout, Action<ResiliencyTryHandler<TException>> tryHandler) where TException : Exception { if (action == null) throw new ArgumentNullException(nameof(action)); while (retryCount-- > 0) { try { action(); return; } catch (TException ex) { //Executa o manipulador de exception if (tryHandler != null) { var callback = new ResiliencyTryHandler<TException>(ex, retryCount); tryHandler(callback); //A propriedade que aborta pode ser alterada pelo cliente if (callback.AbortRetry) throw; } //Aguarda o tempo especificado antes de tentar novamente Thread.Sleep(retryTimeout); } } //Na última tentativa, qualquer exception será lançada de volta ao chamador action(); } } /// <summary> /// Permite manipular o evento de cada tentativa da classe de <see cref="Resiliency"/> /// </summary> public class ResiliencyTryHandler<TException> where TException : Exception { #region Properties /// <summary> /// Opção para abortar o ciclo de tentativas /// </summary> public bool AbortRetry { get; set; } /// <summary> /// <see cref="Exception"/> a ser tratada /// </summary> public TException Exception { get; private set; } /// <summary> /// Identifca o número da tentativa atual /// </summary> public int CurrentTry { get; private set; } #endregion #region Constructors /// <summary> /// Instancia um manipulador de tentativa. É utilizado internamente /// por <see cref="Resiliency"/> para permitir que o cliente altere o /// comportamento do ciclo de tentativas /// </summary> public ResiliencyTryHandler(TException exception, int currentTry) { Exception = exception; CurrentTry = currentTry; } #endregion }