Je n'ai pas de problème; Je suis juste curieux. Imaginez le scénario suivant:
foreach (var foo in list)
{
try
{
//Some code
}
catch (Exception)
{
//Some more code
}
finally
{
continue;
}
}
Cela ne compilera pas, car cela déclenche l' erreur du compilateur CS0157 :
Le contrôle ne peut pas quitter le corps d'une clause finally
Pourquoi?
continue;
enfinally
bloc? n'est-ce pas la même chosecontinue;
qu'après letry -- catch
bloc?finally/continue
c'est une limitation du compilateur C # :-) Je suis également curieux de connaître la raison de cette limitation.br
famille d'instructions de branche ne peut pas accomplir cela.Réponses:
finally
les blocs s'exécutent, qu'une exception soit levée ou non. Si une exception est levée, qu'est-ce que diable feraitcontinue
? Vous ne pouvez pas continuer l'exécution de la boucle, car une exception non interceptée transférera le contrôle à une autre fonction.Même si aucune exception n'est lancée,
finally
s'exécutera lorsque d'autres instructions de transfert de contrôle à l'intérieur du bloc try / catch s'exécutent, commereturn
par exemple, ce qui pose le même problème.Bref, avec la sémantique de
finally
cela n'a pas de sens de permettre le transfert de contrôle de l'intérieur d'unfinally
bloc vers l'extérieur de celui-ci.Soutenir cela avec une sémantique alternative serait plus déroutant qu'utile, car il existe des solutions de contournement simples qui clarifient le comportement prévu. Vous obtenez donc une erreur et êtes obligé de bien réfléchir à votre problème. C'est l'idée générale "vous jeter dans le gouffre du succès" qui se poursuit en C #.
Si vous voulez ignorer les exceptions (le plus souvent est une mauvaise idée) et continuer à exécuter la boucle, utilisez un bloc catch all:
Si vous ne le souhaitez
continue
que lorsqu'aucune exception non interceptée n'est levée, mettez simplement encontinue
dehors du bloc try.la source
continue
dans unfinally
bloc sera OK s'il continue seulement une boucle locale définie à l'intérieur dufinally
bloc. Dans la question, cependant, il essaie de continuer une boucle «externe». Les déclarations similaires que vous ne pouvez pas avoir à l'intérieur d'unfinally
bloc sontreturn
,break
(lors de la sortie du bloc) etgoto
(lors du passage à une étiquette en dehors dufinally
bloc). Pour une discussion Java connexe, consultez Retour d'un bloc finally en Java .Voici une source fiable:
Il est tiré de MSDN, 8.9.2 L'instruction continue .
La documentation dit que:
C'est d'ici 8.10 L'instruction try .
la source
Vous pensez peut-être que cela a du sens, mais cela n'a pas de sens en fait.
Qu'avez-vous l'intention de faire une pause ou une poursuite lorsqu'une exception est levée? L'équipe du compilateur C # ne veut pas prendre de décision par elle-même en supposant
break
oucontinue
. Au lieu de cela, ils ont décidé de se plaindre que la situation du développeur sera ambiguë pour transférer le contrôlefinally block
.C'est donc le travail du développeur d'indiquer clairement ce qu'il a l'intention de faire plutôt que le compilateur en supposant autre chose.
J'espère que vous comprenez pourquoi cela ne compile pas!
la source
finally
instruction serait affecté par le fait que lecatch
soit sorti via une exception, et il n'y a aucun mécanisme pour dire comment cela devrait interagir avec un fichiercontinue
. J'aime votre exemple, car il montre un problème encore plus grave.Comme d'autres l'ont dit, mais en se concentrant sur les exceptions, il s'agit en réalité d'une gestion ambiguë du transfert de contrôle.
Dans votre esprit, vous pensez probablement à un scénario comme celui-ci:
Théoriquement, vous pouvez suivre le flux de contrôle et dire, oui, c'est "ok". Aucune exception n'est levée, aucun contrôle n'est transféré. Mais les concepteurs du langage C # avaient d'autres problèmes en tête.
L'exception lancée
Le redouté Goto
Le retour
La rupture
Donc en conclusion, oui, bien qu'il y ait une légère possibilité d'utiliser un
continue
dans des situations où le contrôle n'est pas transféré, mais bon nombre (la majorité?) Des cas impliquent des exceptions ou desreturn
blocages. Les concepteurs de langage ont estimé que cela serait trop ambigu et (probablement) impossible à garantir au moment de la compilation que votrecontinue
n'est utilisé que dans les cas où le flux de contrôle n'est pas transféré.la source
En général, cela
continue
n'a pas de sens lorsqu'il est utilisé enfinally
bloc. Regarde ça:la source
continue
n'a aucun sens en dehors de l'instruction de boucle, mais cela ne signifie pas qu'elle n'est pas prise en charge.item
peut être un fichier, la lecture a échoué ->finally
ferme le fichier.continue
empêche le reste du traitement.Eh bien, je pense que non.
Quand vous l'avez littéralement,
catch(Exception)
vous n'avez pas besoin de la dernière (et probablement même pas lacontinue
).Lorsque vous avez le plus réaliste
catch(SomeException)
, que doit-il se passer lorsqu'une exception n'est pas interceptée? Vouscontinue
voulez aller dans un sens, l'exception en gérant une autre.la source
finally
quand vous en avezcatch
. Il est couramment utilisé pour fermer les ressources de manière fiable.return
déclaration dans vos blocstry
oucatch
. Qu'est-ce qu'on fait maintenant? Revenir ou continuer la boucle? (et si nous continuons, que se passe-t-il si c'est le dernier élément à itérer? Ensuite, nous continuons juste en dehors deforeach
et le retour ne se produit jamais?) EDIT: Ou mêmegoto
vers une étiquette en dehors de la boucle, à peu près toute action qui transfère le contrôle en dehors de laforeach
boucle .return
s supplémentaires à l'intérieur du bloc. Mais normalement, l'exécution se poursuit après le fourre-tout.Vous ne pouvez pas quitter le corps d'un bloc final. Cela inclut les mots clés break, return et dans votre cas continue.
la source
Le
finally
bloc peut être exécuté avec une exception en attente d'être relancée. Cela n'aurait pas vraiment de sens de pouvoir sortir du bloc (par uncontinue
ou quoi que ce soit d'autre) sans relancer l'exception.Si vous voulez continuer votre boucle quoi qu'il arrive, vous n'avez pas besoin de l'instruction finally: attrapez simplement l'exception et ne la relancez pas.
la source
finally
s'exécute qu'une exception non interceptée soit lancée ou non. D'autres ont déjà expliqué pourquoi cela rendcontinue
illogique, mais voici une alternative qui suit l'esprit de ce que ce code semble demander. Fondamentalement,finally { continue; }
c'est dire:(1) pourrait être satisfait en plaçant
continue
à la fin de chacuncatch
, et (2) pourrait être satisfait en stockant les exceptions non interceptées à lever plus tard. Vous pouvez l'écrire comme ceci:En fait,
finally
aurait également exécuté dans le troisième cas, où il n'y avait aucune exception lancée, pris ou non. Si cela était souhaité, vous pourriez bien sûr en placer uncontinue
après le bloc try-catch au lieu de l'intérieur de chacuncatch
.la source
Techniquement parlant, c'est une limitation du CIL sous-jacent. À partir de la spécification de langue :
et
Sur la page doc pour les
br
instructions :Ce dernier est vrai pour toutes les instructions de branchement, y compris
beq
,brfalse
, etc.la source
Les concepteurs du langage ne voulaient tout simplement pas (ou ne pouvaient pas) raisonner sur la sémantique d'un bloc finally terminé par un transfert de contrôle.
Un problème, ou peut-être le problème clé, est que le
finally
bloc est exécuté dans le cadre d'un transfert de contrôle non local (traitement d'exception). La cible de ce transfert de contrôle n'est pas la boucle englobante; le traitement d'exception interrompt la boucle et continue le déroulement.Si nous avons un transfert de contrôle hors du
finally
bloc de nettoyage, alors le transfert de contrôle d'origine est "détourné". Il est annulé et le contrôle va ailleurs.La sémantique peut être élaborée. D'autres langues l'ont.
Les concepteurs de C # ont décidé de simplement interdire les transferts de contrôle statiques, «goto», simplifiant ainsi quelque peu les choses.
Cependant, même si vous faites cela, cela ne résout pas la question de savoir ce qui se passe si un transfert dynamique est lancé à partir d'un
finally
: que se passe-t-il si le bloc finally appelle une fonction et que cette fonction lève? Le traitement des exceptions d'origine est alors "détourné".Si vous travaillez sur la sémantique de cette seconde forme de piratage, il n'y a aucune raison de bannir le premier type. C'est vraiment la même chose: un transfert de contrôle est un transfert de contrôle, qu'il ait la même portée lexicale ou non.
la source
finally
par définition, il faut immédiatement suivre la poursuite du transfert qui l'a déclenché (une exception non interceptéereturn
, etc.). Il serait facile d'autoriser les transferts "goto-like" à l'intérieurfinally
(quelles langues font cela, d'ailleurs?), Mais cela signifierait que celatry { return } finally { ... }
pourrait ne pas revenir , ce qui est complètement inattendu. Si vousfinally
appelez une fonction qui lance, ce n'est pas vraiment la même chose, car nous nous attendons déjà à ce que des exceptions se produisent à tout moment et interrompent le flux normal.finally
est en quelque sorte la même chose, en ce sens qu'elle peut entraîner un flux de programme inattendu et illogique. La seule différence est que les concepteurs de langage, étant incapables de rejeter tous les programmes où un bloc finally pourrait lever une exception non gérée, autorisent à la place ces programmes à se compiler et espèrent que le programme pourra accepter toutes les conséquences qui pourraient suivre l'abandon de l'exception précédente. séquence.finally
ou non. Selon la logique du dernier paragraphe de Kaz, les fonctions devraient également être libres d'affecter le flux dans la portée de leur appelant par le biais decontinue
etc., car elles sont autorisées à le faire à titre d'exceptions. Mais cela n'est bien sûr pas autorisé; les exceptions sont la seule exception à cette règle, d'où le nom «exception» (ou «interruption»).finally
bloc peut la violer. Vraiment une situation désagréable, qui à mon humble avis aurait dû être résolue en informant au minimum lesfinally
blocs de toutes les exceptions en attente afin qu'ils puissent créer des objets d'exception composites.