2014-10-09 6 views
3

используя goto кажется естественным здесь.Могу ли я заменить эту инструкцию GOTO на C#

Проект должен читать pdf-файл, файл pdf может быть одним из следующих.

  • Не Protected
  • Protected с password1
  • Protected с password2
  • Protected с 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; 
} 

Вставить попытку/уловку работать, но выглядит уродливым, используя goto seem natural.

Два вопроса:

  1. Должен ли я заменить этот Гото?
  2. Есть ли элегантный способ заменить этот goto?

Благодаря

+2

Да, вы должны. Почему в мире вы бы не использовали цикл? Вы эмулируете один с 'goto' ... в C# –

+4

Никогда не используйте' throw ex' для восстановления исключения, вместо этого просто используйте 'throw'. 'throw ex' не будет сохранять исходную стеклу, как это делает throw. Это будет очень полезно для дедуплирования. –

+0

Простой 'while (Retries <= 3)' достаточно для замены 'goto' здесь. 'Switch()' также не является высотой элегантности. –

ответ

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. Вы определили список паролей, чтобы попытаться не включая «None»
  2. You не заботятся о BadPasswordExceptions кроме игнорировать их
  3. Если вы получаете удар, то цикл выходит
  4. Если вы не получаете хитов цикл завершается в конце

Другое дело, что ваш код с тремя паролями немного хрупкий, если вам приходится иметь дело с более или менее паролями. И я думаю, что использование переменной типа passwordsToTry прекрасно вписывается в инструкцию «try».

+0

фиксированный обе goto & переключатель выпуск. Большой! – Rm558

+0

Это нормально завершается, если он терпит неудачу, но в соответствии с вопросом он должен отменить последнее исключение. –

4

Готы, так же, как АЭС или бекон, по сути не является злом. Это вопрос того, что вы с ним делаете.

Текущий код довольно четко структурирован. 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

Это не так «четко структурировано», как могло бы быть. –

+1

Вместо того, чтобы вводить 'passwordIsOk', я бы поставил' break; 'после закрытия скобки' switch'. –

+0

@GregHewgill: Также неплохая идея. Мой личный стиль должен быть довольно явным в том, что происходит, даже если это означает дополнительную строку кода. Я чувствую, что он имеет тенденцию уменьшать ошибки, когда я или кто-то еще поддерживает код спустя годы. Ваше предложение в моей книге прекрасное. Это достаточно понятно для разумного сопровождающего. –

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.

 Смежные вопросы

  • Нет связанных вопросов^_^