尝试/捕获异常从导致异常的行继续

时间:2011-08-19 17:42:23

标签: c#

当抛出异常时,如何捕获它然后从导致错误的行开始继续执行?

编辑: 我们的程序与Indesign Server进行通信,Indesign Server一直崩溃并抛出随机的COM相关错误(这些错误与服务器本身的错误有关)。 Indesign Server也需要很长时间来处理命令,因此当它崩溃时,我们希望避免重新启动执行。相反,我们希望从导致异常的行继续。程序中的任何行都可能导致异常。从技术上讲,我们不能使用循环。

4 个答案:

答案 0 :(得分:12)

  

当抛出异常时,如何捕获它然后从导致错误的行开始继续执行? (不是下一行;重试导致异常的行。)

不要试图这样做。你正在从错误的方向接近这个问题。

问题是你有一个不可靠的子系统。您有一个处理该不可靠子系统的所需策略,即重试该操作直到成功为止。如果是这种情况,则不要将该逻辑放在使用子系统的业务线代码中。业务线代码应该是关于业务逻辑的,而不是关于您选择处理片状子系统的机制。 将机制隔离到特定类,使不可靠的子系统成为可靠的子系统。

即,构建一个与不可靠子系统具有相同接口的代理类,并将重试逻辑隔离到该代理类中。然后,业务线代码可以使用代理类作为可靠的子系统。

也就是说,“重审它直到它运作”的政策可能是一个糟糕的政策。如果子系统真正被打破并且不仅仅是以某种短暂的方式存在片状,那么“重试直到它工作”意味着“永远等待”,并且大多数用户不喜欢永远等待。例如,如果异常是由于路由器被拔掉而不是某些瞬态情况,那么就坐在循环中直到有人将路由器插回来似乎是一个坏主意。

答案 1 :(得分:3)

您必须将任何可能在其try / catch块中引发异常的行包围起来。

所以而不是

try
{
    StatementOne();  // Exception thrown here
    StatementTwo();
}
catch (SOneException) { ... }

你必须这样做:

try
{
    StatementOne();
}
catch (SOneException) { ... }

StatementTwo();

如果由于(希望是瞬态)异常而需要重试某个操作,可以使用如下方法:

public static class ExceptionHelper
{
    public static void TryNTimesAndThenThrow(Action statement, int retryCount)
    {
        bool keepTrying = false;
        do
        {
            try
            {
                statement();
                keepTrying = false;
            }
            catch (Exception)
            {
                if (retryCount > 0)
                {
                    keepTrying = true;
                    retryCount--;
                }
                else
                {
                    // If it doesn't work here, assume it's broken and rethrow
                    throw;
                }
            }
        } while (keepTrying)
    }
}

然后你可以写:

ExceptionHelper.TryNTimesAndThenThrow(() => MightThrowATransientException(), 3);

请记住,应谨慎使用这两种方法。前者会使你的代码混乱很多,而后者可能会花费比你想象的更多的时间(因为如果出现意外情况,通常会更好地提醒用户。因此强调一个瞬态异常,你如果你再试一次,真的会期望会消失。)

答案 2 :(得分:3)

如果你正在寻找一些通用的东西,那么使用lambda就可以了。例如

public static class Exception {
  public static void Continue(Action action) {
    try {
      action();  
    } catch { 
      // Log 
    }
  }
}

Exception.Continue(() => Statement1());
Exception.Continue(() => Statement2());

我不认为这是大规模使用的理想解决方案。它会为您使用此语句的每个语句导致额外的委托分配,委托调用和方法调用。相反,我会专注于识别导致问题的函数,并为它们单独添加显式包装。

答案 3 :(得分:0)

你可以这样做:

                //Retry logic on opening the connection
                int retries = 0;
                openconnection:
                    try
                    {
                        connection.Open();
                    }
                    catch
                    {
                        retries++;
                        //Wait 2 seconds
                        System.Threading.Thread.Sleep(2000);
                        if (retries < MAXRETRIES)
                        {
                            goto openconnection;
                        }
                        else
                        {
                            throw;
                        }
                    }