简体   繁体   English

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

[英]Can/Should I replace this GOTO statement in C#

using goto seems natural in here . 使用goto在这里看起来很自然

A project needs to read pdf file, a pdf file can be one of below. 一个项目需要阅读pdf文件,pdf文件可以是下面的一个。

  • Not Protected 不受保护
  • Protected with password1 用password1保护
  • Protected with password2 受password2保护
  • Protected with password3 受password3保护

A file can only be accessed with correct password, there is no way to know which password the file need upfront. 只能使用正确的密码访问文件,无法预先知道文件需要哪个密码。 we have to try all cases, (include no password). 我们必须尝试所有情况,(不包括密码)。 if none of above password works, throw exception. 如果以上密码均无效,则抛出异常。

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

Embed try/catch is working but looks ugly, using goto seem natural. 嵌入式try / catch正在运行,但看起来很难看,使用goto看起来很自然。

Two questions: 两个问题:

  1. Should I replace this goto? 我应该替换这个转到吗?
  2. Is there an elegant way to replace this goto? 是否有一种优雅的方式来取代这个goto?

Thanks 谢谢

Goto, just like nuclear power or bacon, is not inherently evil. Goto,就像核能或培根一样,本身并不是邪恶的。 It's a matter of what you do with it. 这是你用它做什么的问题。

The current code is fairly clearly structured. 目前的代码结构清晰。 Goto is not being used to create spaghetti code . Goto不会被用来创建意大利面条代码

Having said that, I would still replace it with a while loop. 话虽如此,我仍然会用while循环替换它。 Goto can be a slippery slope. 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".
}

I think you should replace the goto in this case as to me the issue is that your code and retries are clouding the intent. 我认为你应该在这种情况下替换goto,因为我的问题是你的代码和重试使意图蒙上阴影。 I personally would replace the code with something like this: 我个人会用这样的代码替换代码:

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

To me the code is clearer as it shows: 对我来说,代码更清晰,因为它显示:

  1. You have defined list of passwords to try including 'none' 您已定义密码列表以尝试包括“无”
  2. You don't care about BadPasswordExceptions except to ignore them 您不关心BadPasswordExceptions,除非忽略它们
  3. If you get a hit then the loop exits 如果你得到一个命中,那么循环退出
  4. If you get no hits the loop exits at the end 如果没有命中,则循环退出

The other thing is that your code with 3 passwords is slightly brittle if you had to deal with more or less passwords. 另一件事是,如果您不得不处理更多或更少的密码,那么带有3个密码的代码会稍微脆弱。 And I think using a variable like passwordsToTry fits nicely with the 'try' statement. 我认为使用像passwordsToTry这样的变量可以很好地适应'try'语句。

You can do a while(true) with a break : 你可以break while(true)

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 avoids adding any extra variables. 这可以避免添加任何额外的变量。 This topic goes over pros/cons of goto . 本主题讨论goto优点/缺点。

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

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