到目前为止,我实现了这个:
public class Retrier
{
/// <summary>
/// Execute a method with no parameters multiple times with an interval
/// </summary>
/// <typeparam name="TResult"></typeparam>
/// <param name="function"></param>
/// <param name="tryTimes"></param>
/// <param name="interval"></param>
/// <returns></returns>
public static TResult Execute<TResult>(Func<TResult> function, int tryTimes, int interval)
{
for (int i = 0; i < tryTimes - 1; i++)
{
try
{
return function();
}
catch (Exception)
{
Thread.Sleep(interval);
}
}
return function();
}
/// <summary>
/// Execute a method with 1 parameter multiple times with an interval
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="function"></param>
/// <param name="arg1"></param>
/// <param name="tryTimes"></param>
/// <param name="interval"></param>
/// <returns></returns>
public static TResult Execute<T, TResult>(Func<T, TResult> function, T arg1, int tryTimes, int interval)
{
for (int i = 0; i < tryTimes - 1; i++)
{
try
{
return function(arg1);
}
catch (Exception)
{
Thread.Sleep(interval);
}
}
return function(arg1);
}
/// <summary>
/// Execute a method with 2 parameters multiple times with an interval
/// </summary>
/// <typeparam name="T1"></typeparam>
/// <typeparam name="T2"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="function"></param>
/// <param name="arg1"></param>
/// <param name="arg2"></param>
/// <param name="tryTimes"></param>
/// <param name="interval"></param>
/// <returns></returns>
public static TResult Execute<T1, T2, TResult>(Func<T1, T2, TResult> function, T1 arg1, T2 arg2, int tryTimes, int interval)
{
for (int i = 0; i < tryTimes - 1; i++)
{
try
{
return function(arg1, arg2);
}
catch (Exception)
{
Thread.Sleep(interval);
}
}
return function(arg1, arg2);
}
}
问题是它变得很难维护。当我有一个包含更多变量的方法时,我需要实现另一个Execute
方法。如果我需要改变任何东西,我必须在所有方法中改变它。
所以我想知道是否有一种干净的方法使它成为一个方法,可以处理任何数量的参数?
4条答案
按热度按时间jv4diomz1#
正如您所说,您当前的设计不支持n和n+1参数而无需更改代码。
这里有两个常见的做法,可以来拯救。
预先定义变量
如果您查看
Action
和Func
委托,则可以看到从没有参数到16个参数的多个变体。在
Execute
的情况下,你可以遵循同样的概念。这里的美妙之处在于,你可以通过T4生成这个代码。预期匿名函数
而不是有少数重载,您可以涵盖所有情况下与此
以及所有异步情况:
这里的技巧是如何传递参数
一个二个一个一个
所以,我们用下面的四个方法,你可以涵盖所有的方法和函数,不管它们是同步的还是异步的
uidvcgyl2#
您已经可以使用部分应用程序处理任意参数。
这是函数式编程 * 和 * LINQ中的一种常用技术-
Where
操作需要一个Func<T,bool>
,它通常涉及T
类型之外的变量和成员,例如:这在每次调用委托时都会分配一个新的委托,这就是为什么一些库会为多个参数重载,纯粹是出于性能方面的考虑。
jm81lzqq3#
我做了一个名为Mulligan的nuget包来完成这个任务;如果你不想使用我的包,你至少可以看到一个重试的例子。我创建这个包是因为我想使用TestStack.White库之外的retry code,而不是每次都复制和粘贴它。Mulligan的核心功能可以在Retry.cs中找到。
你也可以看看Polly是如何实现它们的重试逻辑的,如果你真的需要自己重新实现它,而且它不是.NET代码,但是这个library也是一个彻底的实现。每当我有时间的时候,我计划尽可能多地查看这些库和移植到mulligan,所以你可能会发现这是一个有用的灵感来源。
希望这些并列的例子能为您提供一些很好的例子,以及不同成熟度级别的实现之间的进展。
acruukt94#
要想真正的通用,你的函数必须有各种各样的原型来处理不同数量的参数,out,ref,async等等。多么痛苦!幸运的是,它根本不需要处理参数。与其 Package 函数,不如 Package 该函数的 * 调用 *,包括参数的赋值。
然后你只需要像这样调用它:
或者
或者
如果你也想处理async,可以再添加一个prototype,这样调用者就可以访问任务了(所以你可以使用
Task.Delay
而不是Sleep
):然后像这样使用: