Je suis tombé sur cette nouvelle fonctionnalité en C # qui permet à un gestionnaire de capture de s'exécuter lorsqu'une condition spécifique est remplie.
int i = 0;
try
{
throw new ArgumentNullException(nameof(i));
}
catch (ArgumentNullException e)
when (i == 1)
{
Console.WriteLine("Caught Argument Null Exception");
}
J'essaie de comprendre quand cela peut être utile.
Un scénario pourrait être quelque chose comme ceci:
try
{
DatabaseUpdate()
}
catch (SQLException e)
when (driver == "MySQL")
{
//MySQL specific error handling and wrapping up the exception
}
catch (SQLException e)
when (driver == "Oracle")
{
//Oracle specific error handling and wrapping up of exception
}
..
mais c'est encore quelque chose que je peux faire dans le même gestionnaire et déléguer à différentes méthodes en fonction du type de pilote. Cela rend-il le code plus facile à comprendre? Sans doute non.
Un autre scénario auquel je peux penser est quelque chose comme:
try
{
SomeOperation();
}
catch(SomeException e)
when (Condition == true)
{
//some specific error handling that this layer can handle
}
catch (Exception e) //catchall
{
throw;
}
Encore une fois, c'est quelque chose que je peux faire comme:
try
{
SomeOperation();
}
catch(SomeException e)
{
if (condition == true)
{
//some specific error handling that this layer can handle
}
else
throw;
}
L'utilisation de la fonctionnalité «catch, when» accélère-t-elle la gestion des exceptions car le gestionnaire est ignoré en tant que tel et le déroulement de la pile peut se produire beaucoup plus tôt que la gestion des cas d'utilisation spécifiques dans le gestionnaire? Y a-t-il des cas d'utilisation spécifiques qui correspondent mieux à cette fonctionnalité que les gens peuvent ensuite adopter comme bonne pratique?
la source
when
besoin d'accéder à l'exception elletry..catch...catch..catch..finally
?catch (Exception ex)
, vérifier le type etthrow
autrement. Un code légèrement plus organisé (évitant le bruit de code) est exactement la raison pour laquelle cette fonctionnalité existe. (C'est en fait vrai pour beaucoup de fonctionnalités.)Réponses:
Les blocs de capture vous permettent déjà de filtrer sur le type de l'exception:
La
when
clause vous permet d'étendre ce filtre aux expressions génériques.Ainsi, vous utilisez la
when
clause pour les cas où le type de l'exception n'est pas suffisamment distinct pour déterminer si l'exception doit être traitée ici ou non.Un cas d'utilisation courant est celui des types d'exception qui sont en fait un wrapper pour plusieurs types d'erreurs différents.
Voici un cas que j'ai réellement utilisé (en VB, qui possède déjà cette fonctionnalité depuis un certain temps):
Idem pour
SqlException
, qui a aussi uneErrorCode
propriété. L'alternative serait quelque chose comme ça:ce qui est sans doute moins élégant et casse légèrement la trace de la pile .
De plus, vous pouvez mentionner le même type d'exception deux fois dans le même bloc try-catch-block:
ce qui ne serait pas possible sans la
when
condition.la source
catch
, n'est-ce pas?when
vous permet de gérer le même type d'exception plusieurs fois. Vous devriez le mentionner également car c'est une différence cruciale. Sanswhen
cela, vous obtiendrez une erreur de compilation.Du wiki de Roslyn (c'est moi qui souligne):
Le premier point mérite d'être démontré.
Si nous exécutons ceci dans WinDbg jusqu'à ce que l'exception soit atteinte, et imprimons la pile en utilisant,
!clrstack -i -a
nous verrons juste le cadre deA
:Cependant, si nous changeons le programme à utiliser
when
:Nous verrons que la pile contient également
B
le cadre de:Ces informations peuvent être très utiles lors du débogage des vidages sur incident.
la source
throw;
(par opposition àthrow ex;
) la pile indemne également? +1 pour l'effet secondaire. Je ne suis pas sûr d'approuver cela, mais il est bon de connaître cette technique.throw;
, la pile se déroule et vous perdez les valeurs des paramètres.throw;
change un peu la trace de la pile et lathrow ex;
change beaucoup.throw
perturbe légèrement la trace de la pile. Les numéros de ligne sont différents lors de l'utilisationthrow
par opposition àwhen
.Lorsqu'une exception est levée, la première passe de la gestion des exceptions identifie où l'exception sera interceptée avant de dérouler la pile; si / quand l'emplacement "catch" est identifié, tous les blocs "finalement" sont exécutés (notez que si une exception échappe à un bloc "finalement", le traitement de l'exception précédente peut être abandonné). Une fois que cela se produit, le code reprendra l'exécution à la "capture".
S'il y a un point d'arrêt dans une fonction qui est évalué dans le cadre d'un «quand», ce point d'arrêt suspendra l'exécution avant que tout déroulement de pile ne se produise; en revanche, un point d'arrêt à un "catch" ne suspendra l'exécution qu'après que tous les
finally
gestionnaires se soient exécutés.Enfin, si les lignes 23 et 27 de l'
foo
appelbar
, et l'appel sur la ligne 23 jette une exception qui est interceptéefoo
et renvoyée sur la ligne 57, alors la trace de pile suggérera que l'exception s'est produite lors de l'appel àbar
partir de la ligne 57 [emplacement de la relance] , détruisant toute information indiquant si l'exception s'est produite dans l'appel de la ligne 23 ou de la ligne 27. Utiliserwhen
pour éviter d'attraper une exception évite en premier lieu une telle perturbation.BTW, un modèle utile qui est gênant à la fois en C # et en VB.NET consiste à utiliser un appel de fonction dans une
when
clause pour définir une variable qui peut être utilisée dans unefinally
clause pour déterminer si la fonction s'est terminée normalement, pour gérer les cas où une fonction n'a aucun espoir de «résoudre» toute exception qui se produit, mais doit néanmoins prendre des mesures en fonction de celle-ci. Par exemple, si une exception est levée dans une méthode de fabrique qui est censée renvoyer un objet qui encapsule des ressources, toutes les ressources qui ont été acquises devront être libérées, mais l'exception sous-jacente doit percoler jusqu'à l'appelant. La façon la plus propre de gérer cela sémantiquement (mais pas syntaxiquement) est d'avoir unfinally
bloquer vérifier si une exception s'est produite et, si tel est le cas, libérer toutes les ressources acquises au nom de l'objet qui ne sera plus renvoyé. Puisque le code de nettoyage n'a aucun espoir de résoudre la condition qui a causé l'exception, il ne devrait vraiment pas lecatch
faire, mais a simplement besoin de savoir ce qui s'est passé. Appel d'une fonction comme:dans une
when
clause permettra à la fonction factory de savoir que quelque chose s'est passé.la source