尝试catch直到成功-针对泛型方法或委托的执行循环

本文关键字:循环 执行 泛型方法 catch 成功 -针 尝试 | 更新日期: 2023-09-27 17:58:37

我希望我的代码继续尝试一个方法,直到没有抛出异常,但是,与这个问题不同的是,我希望它被编写为一个能够运行任何输入委托/方法的通用方法。以下是我的想法,但我不确定如何通过它传递参数或通用方法:

public void tryLoop(Delegate anyMethod, T[] arguments) {
    while (true) {                              
        // Could be replaced by timer timeout
        try {
            anyMethod(arguments);
            break;
        }
        catch {
            System.Threading.Thread.Sleep(2000); // wait 2 seconds
        }
    }
}

这可能吗?

编辑:对于学术界来说,我也想知道是否也可以返回结果。

尝试catch直到成功-针对泛型方法或委托的执行循环

如果您可以接受使用闭包,则不需要将参数全部传递给此方法(或具有多个重载)。可以使用Func返回结果。

  public T tryLoop<T>(Func<T> anyMethod)
  {
     while (true)
     {
        try
        {
           return anyMethod();
        }
        catch
        {
           System.Threading.Thread.Sleep(2000); // *
        }
     }
     return default(T);
  }

  void SomeMethod(int param)
  {
     var someLocal = "Hi";
     var anotherLocal = 0;
     var result = tryLoop(() =>
     {
        Console.WriteLine(someLocal);
        return param + anotherLocal;
     });
     Console.Write(result);
  }

然而,老实说,我不会设置无限重试——充其量,如果返回某些类型的retryable错误,例如数据库死锁或调用不稳定web服务的超时,那么可能需要3或4次重试。DivideByZeroFileNotFound等异常不太可能通过无限期运行而消失:-)

***特别是对于死锁,建议随机休眠一段时间,以防其他线程也在完全相同的数据上同时死锁-您不希望在2000毫秒内再次发生相同的死锁:-)。

一种方法是使用Action,并删除arguments参数:

public void tryLoop(Action anyMethod) {
    while ( true ) {
        // Could be replaced by timer timeout
        try {
            anyMethod();
            break;
        }
        catch {
            System.Threading.Thread.Sleep(2000); // wait 2 seconds
        }
    }
}

这给了你使用它的终极自由:

tryLoop(() => string.Reverse("abc"));

或者像这样:

String s1 = "A";
String s2 = "b";
tryLoop(() => string.Concat(s1, s2));

正如您在第二个示例中看到的,您可以直接从被调用的tryLoop方法的上下文中获取参数。你可以在那里调用任何东西。

这种方法的好处是,您不必像使用Delegate而不是Action那样使用InvokeDynamicInvoke,因为这会带来性能损失。

如果你需要结果,你可以用Func<T>而不是Action重写上面的内容,如下所示:

public T tryLoop<T>(Func<T> anyMethod) {
    while ( true ) {
        // Could be replaced by timer timeout
        try {
            return anyMethod();
        }
        catch {
            System.Threading.Thread.Sleep(2000); // wait 2 seconds
        }
    }
}

并像这样使用:

var reversed = tryLoop(() => string.Reverse("abc"));
String s1 = "A";
String s2 = "b";
var concatenated = tryLoop(() => string.Concat(s1, s2));

检查这是否符合您的需求。如果没有,请发表评论。也不确定它的性能如何。

此外,DynamicInvoke方法具有object返回类型。您可以使用它来返回委托的结果。您可以将方法的返回类型从void更改为object

public void tryLoop<T>(Delegate anyMethod, T[] arguments)
{
    while (true)
    {                              // Could be replaced by timer timeout
        try
        {
            anyMethod.DynamicInvoke(arguments);
            break;
        }
        catch
        {
            System.Threading.Thread.Sleep(2000); // wait 2 seconds
        }
    }
}

希望这能帮助