2010-10-17 22 views
1

Voici pseudocode:L'utilisation de "goto" est-elle acceptable dans cette situation?

myGoto: 
try 
{ 
    // do some db updating 
    myDB.doOptimisticConcurrency(); 

} catch (MyConcExeption ex) { 

    if (tried < fiveTimes) { 
     myDB.Refresh(); 
     tried++; 
     goto myGoto; 
    } 

} 

J'ai plusieurs blocs try-catch dans une méthode, et je ne veux pas en relançant ma méthode depuis le début de toute exception lancée. L'utilisation de goto est-elle acceptable dans cette situation?

+1

Aw. Ça fait mal d'essayer de comprendre ça. – xtofl

+0

À la reprise de l'erreur Suivant –

Répondre

16

Vous pouvez le changer:

while (tried < fiveTimes) 
try 
{ 
    // do some db updating 
    myDB.doOptimisticConcurrency(); 
    break; 
} 
catch (MyConcExeption ex) 
{ 
    tried++; 
    myDB.Refresh(); 
} 
+1

Note qu'à la fin de cette boucle, vous devrez alors tester 'tried' pour savoir si oui ou non il a réussi. Je préférerais généralement une exception après que les tentatives aient toutes échoué. –

+1

@Jon - C'est vrai pour le code dans la question aussi, je viens de montrer comment l'écrire sans goto. – Giorgi

+1

Accordé, mais je pense qu'il vaut la peine de le signaler comme une faille dans le code d'origine. Je soupçonne qu'il est très rare que vous vouliez continuer comme si rien ne s'était passé après plusieurs tentatives. –

2

L'utilisation de goto n'est presque jamais acceptable, elle conduit à spaghetti code et rend votre code moins lisible.

Dans votre cas, une simple boucle rendrait votre code plus lisible.

alt text

+5

Incorrect. GOTO peut améliorer votre code s'il est utilisé à bon escient. Par exemple, en C, il peut être utile d'encapsuler le code de gestion des erreurs dans un endroit si de nombreux appels dans une fonction peuvent échouer. Cela dit, je n'ai jamais trouvé le besoin de l'utiliser en C#, et je n'aime pas l'exemple de l'OP. Les absolus sont rarement corrects cependant. –

+0

@Ed Swangren, j'ai tempéré ma déclaration;) –

+1

Ok, maintenant je suis d'accord. Retiré mon downvote :) –

3

Vous pouvez simplement utiliser une boucle.

1

Vous ne devriez pas être lancer une exception si la situation est, bien, exceptionnel. Pourquoi n'ajoutez-vous pas un nouvel argument à cette méthode et ne lancez l'exception en interne que si le nombre de tentatives est dépassé?

EDIT: Comme d'autres l'ont suggéré, une boucle est également une meilleure alternative. Cependant, cela ressemble à votre méthode, pas une méthode enveloppée dans une bibliothèque que vous ne pouvez pas modifier. Si je suis correct, je continuerais avec le paramètre retry et ne lancerais une exception que si toutes les tentatives échouaient. Si vous pensez que cette méthode échouera parfois lors de la première tentative, cela ne devrait pas être une exception.

13

Je n'utiliserais pas "goto" - mais vous pourriez écrire une petite méthode d'aide. Par exemple:

public static void TryMultiple<E>(Action action, int times) where E : Exception 
{ 
    E lastException = null; 
    for (int i = 0; i < times; i++) 
    { 
     try 
     { 
      action(); 
      return; // Yay, success! 
     } 
     catch (E exception) 
     { 
      // Possibly log? 
      lastException = exception; 
     } 
    } 
    throw new RetryFailedException("Retry failed " + times + " times", 
            lastException); 
} 

Ceci est juste un croquis de la solution - vous voudrez l'adapter en conséquence. Quoi qu'il en soit, cela vous permet essentiellement d'effectuer des tentatives dans le cadre d'une exception semi-acceptée de manière réutilisable. Vous utiliserez probablement une expression lambda pour exprimer l'action, ou parfois juste un groupe de méthode pour un seul appel de méthode:

TryMultiple<MyConcurrencyException>(myDB.doOptimisticConcurrency, 5); 
-1

Ceci est beaucoup mieux:

private void MyMethod() 
{ 
    MyMethod(5); 
}  

private void MyMethod(int triesLeft) 
{ 
    if(triesLeft == 0) 
     return; // or throw 

    try 
    { 
     // do some db updating 
     myDB.doOptimisticConcurrency(); 
    }  
    catch (MyConcExeption ex) 
    { 
     myDB.Refresh(); 
     MyMethod(triesLeft - 1); 
    } 
} 
+4

C'est une boucle! Pourquoi y apporter la récursion? – SoftMemes

+0

Les boucles et la récursivité sont équivalentes. – Ani

+0

ouais ...n'écrivons pas Lisp en C# si nous pouvons l'éviter en utilisant une simple boucle s'il vous plait. –