可以/应该在C#中替换此GOTO语句

时间:2014-10-09 21:46:37

标签: c# try-catch goto readability

使用goto在这里看起来很自然

项目需要阅读pdf文件,pdf文件可以是以下之一。

  • 不受保护
  • 使用password1
  • 保护
  • 使用password2保护
  • 使用password3保护

只能使用正确的密码访问文件,无法预先知道文件需要哪个密码。我们必须尝试所有情况,(不包括密码)。如果以上密码均无效,则抛出异常。

PdfReader GetPdfReader(string filePath)
{
    PdfReader r = null;
    int Retries = 0;
    start: try
    {
        switch (Retries)
        {
            case 0: r = new PdfReader(filePath); break;
            case 1: r = new PdfReader(filePath, password1); break;
            case 2: r = new PdfReader(filePath, password2); break;
            case 3: r = new PdfReader(filePath, password3); break;
        }
    }
    catch (BadPasswordException ex)
    {
        if (Retries == 3) throw ex;
        Retries++;
        goto start;
    }
    return r;
}

嵌入式try / catch正在运行,但看起来很难看,使用goto看起来很自然。

两个问题:

  1. 我应该更换这个转到吗?
  2. 有没有一种优雅的方式来替换这个goto?
  3. 由于

3 个答案:

答案 0 :(得分:4)

Goto,就像核能或培根一样,本身并不是邪恶的。这是你用它做什么的问题。

目前的代码结构清晰。 Goto不会用于创建spaghetti code

话虽如此,我仍然会用while循环替换它。 Goto可能是一个滑坡。

bool passwordIsOK = false;
while (!passwordIsOK && Retries < 3)
{
    // Existing code, without "goto start;".  Set passwordIsOK = true when appropriate.
    // See also @Sriram's comment about using "throw" rather than "throw ex".
}

答案 1 :(得分:2)

我认为你应该在这种情况下替换goto,因为我的问题是你的代码和重试会使意图蒙上阴影。我个人会用这样的代码替换代码:

PdfReader GetPdfReader(string filePath)
{
    PdfReader r = null;

    string [] passwordsToTry = new string [] {null, password1, password2, password3};

    foreach(string password in passwordsToTry)
    {
        try
        {
            r = (password == null) ? 
                new PdfReader(filePath) 
              : new PdfReader(filePath, password);
            if (r != null) 
               break;
        }
        catch(BadPasswordException){ }
    }
    return r;
}

对我而言,代码更清晰,如下所示:

  1. 您已定义了要尝试的密码列表,包括&#39;无&#39;
  2. 您不必关心BadPasswordExceptions,除非忽略它们
  3. 如果你受到了打击,那么循环退出
  4. 如果没有命中,则循环退出
  5. 另一件事是,如果您不得不处理更多或更少的密码,那么带有3个密码的代码会稍微脆弱一些。而且我认为使用像passwordToTry这样的变量可以很好地适应&#39;尝试&#39;言。

答案 2 :(得分:0)

您可以使用while(true)执行break

PdfReader GetPdfReader(string filePath)
{
    PdfReader r = null;
    int Retries = 0;
    while(true)
    {
        try
        {
            switch (Retries)
            {
                case 0: r = new PdfReader(filePath); break;
                case 1: r = new PdfReader(filePath, password1); break;
                case 2: r = new PdfReader(filePath, password2); break;
                case 3: r = new PdfReader(filePath, password3); break;
            }
            break;
        }
        catch (BadPasswordException ex)
        {
            if (Retries == 3) throw ex;
            Retries++;
        }
    }
    return r;
}

这可以避免添加任何额外的变量。 This topic追溯goto的优点/缺点。