繁体   English   中英

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

[英]Try/Catch exception continue from line that caused the exception

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

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

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

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

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

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

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

您必须包围任何可能在其自己的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);

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

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

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

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

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

你可以这样做:

                //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;
                        }
                    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM