2008-09-24 5 views
3

Voici une question pour exposer mon manque d'expérience: J'ai une méthode DoSomething() qui lève une exception si elle ne parvient pas à le faire proprement. Si cela échoue, j'essaie la méthode moins précise DoSomethingApproximately() plusieurs fois dans l'espoir qu'il trouvera une solution suffisamment bonne; si cela échoue également, j'appelle finalement DoSomethingInaccurateButGuaranteedToWork(). Tous les trois sont des méthodes appartenant à cet objet. Deux questions: d'abord, est-ce que ce modèle (certes moche) est acceptable ou existe-t-il un moyen plus élégant?Modèle pour essayer différentes méthodes lorsque l'exception est levée

Deuxièmement, quel est le meilleur moyen de garder une trace du nombre de fois que j'ai appelé DoSomethingApproximately(), étant donné qu'il est susceptible de lever une exception? Je garde actuellement une variable iNoOfAttempts dans l'objet, et l'imbrication essaie des blocs ... c'est horrible et j'ai honte.

+0

Oui; Je suppose que la plupart des solutions devraient être assez indépendantes des langages, tant que la gestion des exceptions est possible. –

Répondre

4

Vous ne devez jamais utiliser d'exceptions pour le flux de contrôle de votre application.

Dans votre cas, je regrouperais les trois méthodes en une seule méthode et je ferais en sorte que cette approche particulière réussisse, peut-être avec une énumération ou quelque chose comme ça.

+0

Je ne suis pas d'accord. Si DoSomethingApproximately() et DoSomethingThatAlwaysWorks() sont en fait des fonctions de gestion d'erreurs, alors les exceptions peuvent très bien être la bonne façon de le faire. –

+0

Les exceptions doivent être lancées dans des situations inattendues, et non dans les erreurs attendues. Bien sûr, il y a aussi des exceptions à cette règle. –

+0

Oui, bien sûr. Nous devons supposer que DoSomething() fait ce qu'il est censé faire, à moins que quelque chose d'inattendu n'arrive ...;) –

2

Renvoie un code d'erreur au lieu de déclencher une exception. Si les méthodes échouent, les exceptions rejettent les exceptions, les capturent toutes dans la même méthode et prennent les mesures appropriées, comme augmenter un compteur et renvoyer un code d'erreur.

bool result = DoSomething(); 
    while (!result && tries < MAX_TRIES) { 
     result = DoSomethingApproximately(); //This will increment tries 
     if (tries > THRESHOLD) { 
      result = DoSomethingThatAlwaysWorks(); 
     } 
    } 
2

Que diriez-vous (pseudo-code):

try{ return doSomething(); } 
catch(ExpectedException) { ...not much here probably...} 

for(i = 0 to RETRIES){ 
try{ return doSomethingApproximately; } 
catch(ExpectedException) { ...not much here probably...} 
} 

doSomethingGuaranteed(); 

Addendum:

Je recommande fortement que vous ne l'utilisez pas des valeurs spéciales de retour, car cela signifie que chaque utilisateur de la fonction doit savoir que certains des valeurs de retour sont spéciales. En fonction de la plage de la fonction, il peut être judicieux de retourner une partie ordinaire de la plage qui peut être traitée normalement, par ex. une collection vide. Bien sûr, cela peut rendre impossible la distinction entre l'échec et la «bonne» réponse étant la collection vide (dans cet exemple). Accédez à tous les pointeurs de fonction dans une route de structure.

+0

Je souhaite parfois avoir un paramètre permettant à l'appelant d'indiquer si les modes de défaillance communs doivent être indiqués via une exception ou un code de retour. Considérez quelque chose comme "connectez-vous au serveur X avec le justificatif Y". Si l'appelant s'attend à ce que la tentative échoue (par exemple, s'il a une liste de serveurs, et essayera jusqu'à ce qu'il réussisse), avoir la méthode throw une exception n'est pas utile. D'un autre côté, si le code s'attend à ce qu'un login fonctionne simplement, lancer une exception peut éliminer la nécessité d'une vérification des erreurs côté client lors de la tentative, si l'exception lancée est celle que le client peut attraper. – supercat

2

Juste pour pimenter, je vais utiliser une file d'attente et un peu de LINQ.

Queue<Action> actions = new Queue<Action>(new Action[] { 
    obj.DoSomething, 
    obj.DoSomethingApproximately, 
    obj.DoSomethingApproximately, 
    obj.DoSomethingApproximately, 
    obj.DoSomethingApproximately, 
    obj.DoSomethingGuaranteed 
}); 

actions.First(a => { 
    try { 
     a(); 
     return true; 
    } catch (Exception) { 
     return false; 
    } 
}); 
Questions connexes