C# 我可以/应该用C替换这个GOTO语句吗#
在这里使用goto似乎很自然 一个项目需要阅读pdf文件,pdf文件可以是以下文件之一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 {
- 不受保护
- 用密码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未被用于创建 话虽如此,我还是会用
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两个问题。太好了!如果失败,它将正常退出,但根据问题,它应该重新引发最后一个异常。