使用goto在这里看起来很自然。
项目需要阅读pdf文件,pdf文件可以是以下之一。
只能使用正确的密码访问文件,无法预先知道文件需要哪个密码。我们必须尝试所有情况,(不包括密码)。如果以上密码均无效,则抛出异常。
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看起来很自然。
两个问题:
由于
答案 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;
}
对我而言,代码更清晰,如下所示:
另一件事是,如果您不得不处理更多或更少的密码,那么带有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
的优点/缺点。