L’exception Try / Catch continue depuis la ligne qui a provoqué l’exception

Quand une exception est levée, comment puis-je l’attraper puis continuer l’exécution à partir de la ligne qui a provoqué l’erreur?

EDIT: Notre programme communique avec Indesign Server qui se bloque tout le temps et génère des erreurs aléatoires liées à COM (ces erreurs ont à voir avec des bogues dans le serveur lui-même). De plus, Indesign Server prend beaucoup de temps à traiter les commandes. Par conséquent, lorsqu’il se bloque, nous voulons éviter de redémarrer l’exécution. Au lieu de cela, nous voulons continuer à partir de la ligne qui a provoqué l’exception. Toute ligne du programme peut provoquer une exception. Donc techniquement, nous ne pouvons pas utiliser une boucle.

Quand une exception est levée, comment puis-je l’attraper puis continuer l’exécution à partir de la ligne à l’origine de l’erreur? (Pas la ligne suivante; réessayez la ligne qui a provoqué l’exception.)

N’essayez pas de faire ça. Vous abordez ce problème dans la mauvaise direction.

Le problème est que vous avez un sous-système peu fiable. Vous avez une stratégie souhaitée pour traiter ce sous-système peu fiable, qui consiste à relancer l’opération jusqu’à ce qu’elle aboutisse. Si c’est le cas, alors ne placez pas cette logique dans le code métier qui utilise le sous-système . Le code de secteur d’activité doit concerner la logique métier et non le mécanisme que vous choisissez de gérer avec le sous-système flaky. Isolez le mécanisme dans une classe spécifique qui transforme le sous-système peu fiable en un sous-système fiable.

C’est-à-dire, créez une classe proxy qui a la même interface que le sous-système non fiable et isolez votre logique de nouvelle tentative dans cette classe proxy. Ensuite, le code métier peut utiliser la classe proxy en tant que sous-système fiable.

Cela dit, une politique consistant à “réessayer jusqu’à ce que ça marche” est peut-être une mauvaise politique. Si le sous-système est véritablement cassé et qu’il ne s’agit pas simplement d’une partition temporaire, “réessayer jusqu’à ce que cela fonctionne” signifie “attendre pour toujours”, et la plupart des utilisateurs n’aiment pas attendre pour toujours. Par exemple, si l’exception résulte du détwigment d’un routeur plutôt que de certaines conditions transitoires, restr en boucle jusqu’à ce que quelqu’un twig le routeur, semble être une mauvaise idée.

Si vous cherchez quelque chose de général, utilisez un lambda. Par exemple

public static class Exception { public static void Continue(Action action) { try { action(); } catch { // Log } } } Exception.Continue(() => Statement1()); Exception.Continue(() => Statement2()); 

Je ne considérerais pas cela comme une solution idéale pour une utilisation à grande échelle. Cela provoque une allocation de délégué supplémentaire, un appel de délégué et une invocation de méthode pour chaque instruction pour laquelle vous l’utilisez. Au lieu de cela, je me concentrerais sur l’identification des fonctions qui vous causent des problèmes et ajoutais des enveloppes explicites pour chacune d’entre elles.

Pour cela, vous devrez entourer toute ligne qui pourrait générer une exception dans son propre bloc try / catch .

Donc au lieu de

 try { StatementOne(); // Exception thrown here StatementTwo(); } catch (SOneException) { ... } 

Vous devriez faire:

 try { StatementOne(); } catch (SOneException) { ... } StatementTwo(); 

Si vous devez réessayer une opération en raison d’une exception (espérons-le transitoire ), vous pouvez utiliser une méthode comme celle-ci:

 public static class ExceptionHelper { public static void TryNTimesAndThenThrow(Action statement, int retryCount) { bool keepTrying = false; do { try { statement(); keepTrying = false; } catch (Exception) { if (retryCount > 0) { keepTrying = true; retryCount--; } else { // If it doesn't work here, assume it's broken and rethrow throw; } } } while (keepTrying) } } 

Ensuite, vous pouvez simplement écrire:

 ExceptionHelper.TryNTimesAndThenThrow(() => MightThrowATransientException(), 3); 

Gardez à l’esprit que les deux méthodes doivent être utilisées avec parcimonie. Le premier encombrera un peu votre code, tandis que le dernier risque de prendre beaucoup plus de temps que vous ne le pensez (car il est souvent plus judicieux d’alerter simplement l’utilisateur si quelque chose d’inattendu se produit. attendez-vous vraiment à disparaître si vous essayez à nouveau.)

Vous pouvez faire quelque chose comme ça:

  //Retry logic on opening the connection int resortinges = 0; openconnection: try { connection.Open(); } catch { resortinges++; //Wait 2 seconds System.Threading.Thread.Sleep(2000); if (resortinges < MAXRETRIES) { goto openconnection; } else { throw; } }