Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/278.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 我可以/应该用C替换这个GOTO语句吗#_C#_Try Catch_Goto_Readability - Fatal编程技术网

C# 我可以/应该用C替换这个GOTO语句吗#

C# 我可以/应该用C替换这个GOTO语句吗#,c#,try-catch,goto,readability,C#,Try Catch,Goto,Readability,在这里使用goto似乎很自然 一个项目需要阅读pdf文件,pdf文件可以是以下文件之一 不受保护 用密码1保护 用密码2保护 用密码3保护 只有使用正确的密码才能访问文件,无法预先知道文件需要哪个密码。我们必须尝试所有情况(包括没有密码)。如果上述密码均无效,则引发异常 PdfReader GetPdfReader(string filePath) { PdfReader r = null; int Retries = 0; start: try {

在这里使用goto似乎很自然

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

  • 不受保护
  • 用密码1保护
  • 用密码2保护
  • 用密码3保护
只有使用正确的密码才能访问文件,无法预先知道文件需要哪个密码。我们必须尝试所有情况(包括没有密码)。如果上述密码均无效,则引发异常

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看起来很自然

两个问题:

  • 我应该替换这个goto吗
  • 有没有一个优雅的方式来取代这个后藤

  • 谢谢

    后藤,就像核能或培根一样,并非天生邪恶。这是你用它做什么的问题

    当前代码的结构相当清晰。Goto未被用于创建

    话虽如此,我还是会用
    while
    循环替换它<代码>转到可能是一个很滑的斜坡

    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".
    }
    
    bool passwordIsOK=false;
    而(!passwordIsOK&&Retries<3)
    {
    //现有代码,不带“goto start;”。请在适当时设置passwordIsOK=true。
    //另见@Sriram关于使用“throw”而不是“throw ex”的评论。
    }
    
    您可以使用
    中断来执行
    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;
    }
    

    这样可以避免添加任何额外的变量。回顾一下转到的优缺点,我认为你应该在这种情况下更换转到。对我来说,问题是你的代码和重试模糊了目的。我个人会将代码替换为以下内容:

    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;
    }
    
    对我来说,代码更清晰,因为它显示:

  • 您已定义密码列表以尝试包括“无”
  • 除了忽略它们之外,您不关心BadPasswordException
  • 如果你被击中,循环就会退出
  • 如果没有命中,循环将在末尾退出

  • 另一件事是,如果您必须处理更多或更少的密码,那么带有3个密码的代码有点脆弱。我认为使用passwordsToTry这样的变量非常适合“try”语句。

    是的,您应该这样做。你到底为什么不使用循环呢?您正在模拟一个带有
    goto
    。。。在C语言中,永远不要使用
    throw ex
    来重新显示异常,而只需使用
    throw
    throw ex
    不会像throw那样保留原始堆栈跟踪。这将是非常有用的去毛刺。一个简单的
    while(Retries@EdS.:他不是在模拟循环,而是在实现一个循环。
    基本上做了相同的事情。是的,替换它。它没有意义,它会向上移动。从嵌套循环中跳出或跳入嵌套循环可能是一件好事,但在这里,goto没有任何价值。与其引入
    passwordIsOk
    ,我宁愿把
    中断;
    开关的右括号之后
    @GregHewgill:这也不是一个坏主意。我个人的风格是非常明确地说明正在发生的事情,即使这意味着额外的一行代码。我觉得当我或其他人几年后维护代码时,它往往会减少错误。你的建议在我的书中很好。这足够清楚地说明了一个合理的维护者。修复了goto和switch两个问题。太好了!如果失败,它将正常退出,但根据问题,它应该重新引发最后一个异常。