Ce code fait partie d'une application qui lit et écrit dans une base de données connectée ODBC. Il crée un enregistrement dans la base de données, puis vérifie si un enregistrement a été créé avec succès, puis revient true
.
Ma compréhension du flux de contrôle est la suivante:
command.ExecuteNonQuery()
est documenté pour lancer un InvalidOperationException
quand "un appel de méthode n'est pas valide pour l'état actuel de l'objet". Par conséquent, si cela se produisait, l'exécution du try
bloc s'arrêterait, le finally
bloc serait exécuté, puis exécuterait le return false;
en bas.
Cependant, mon IDE prétend que le return false;
code est inaccessible. Et cela semble être vrai, je peux le supprimer et il se compile sans aucune plainte. Cependant, pour moi, il semble qu'il n'y aurait pas de valeur de retour pour le chemin du code où l'exception mentionnée est levée.
private static bool createRecord(String table,
IDictionary<String,String> data,
System.Data.IDbConnection conn,
OdbcTransaction trans) {
[... some other code ...]
int returnValue = 0;
try {
command.CommandText = sb.ToString();
returnValue = command.ExecuteNonQuery();
return returnValue == 1;
} finally {
command.Dispose();
}
return false;
}
Quelle est mon erreur de compréhension ici?
la source
Dispose
explicitement, mais mettezusing
:using (var command = ...) {command.CommandText = sb.ToString(); return command.ExecuteNonQuery(); }
finally
bloc signifie autre chose que vous ne le pensez.Réponses:
Avertissement du compilateur (niveau 2) CS0162
Ce qui veut juste dire, le compilateur comprend suffisamment grâce à l' analyse statique qu'il ne peut pas être atteint et l'omet complètement de l' IL compilé (d'où votre avertissement)
Remarque : vous pouvez prouver ce fait à vous-même en essayant d'accéder au code inaccessible avec le débogueur ou en utilisant un IL Explorer
Le
finally
peut fonctionner sur une exception , (bien que cela mis à part) cela ne change pas le fait (dans ce cas), il sera toujours une exception non interceptée . Ergo, le dernierreturn
ne sera jamais touché malgré tout.Si vous voulez que le code continue sur le dernier
return
, votre seule option est d' attraper l' exception ;Si vous ne le faites pas, laissez-le tel quel et supprimez le fichier
return
.Exemple
Pour citer la documentation
try-finally (référence C #)
enfin
Lorsque vous utilisez tout ce qui prend en charge l'
IDisposable
interface (qui est conçue pour libérer des ressources non gérées), vous pouvez l'envelopper dans uneusing
instruction. Le compilateur générera untry {} finally {}
appel et en interneDispose()
sur l'objetla source
Faux.
finally
n'accepte pas l'exception. Il l'honore et l'exception sera levée comme d'habitude. Il n'exécutera le code que dans le finally avant la fin du bloc (avec ou sans exception).Si vous voulez que l'exception soit avalée, vous devez utiliser un
catch
bloc sans aucunthrow
.la source
return false
car il lancera une exception à la place @EhsanSajjadL'avertissement est que vous ne l'avez pas utilisé
catch
et que votre méthode est essentiellement écrite comme ceci:Puisque vous utilisez
finally
uniquement pour vous débarrasser, la solution préférée est d'utiliser leusing
modèle:Cela suffit, pour assurer ce
Dispose
qu'on appellera. Il est garanti qu'il sera appelé soit après l'exécution réussie du bloc de code, soit après (avant) unecatch
partie de la pile d'appels (les appels des parents sont arrêtés, non?).S'il ne s'agissait pas d'éliminer, alors
suffit, puisque vous n'aurez jamais à revenir
false
à la fin de la méthode (il n'y a pas besoin de cette ligne). Votre méthode renvoie le résultat de l'exécution de la commande (true
oufalse
) ou lèvera une exception dans le cas contraire .Envisagez également de lever vos propres exceptions en encapsulant les exceptions attendues (consultez le constructeur InvalidOperationException ):
Ceci est généralement utilisé pour dire quelque chose de plus significatif (utile) à l'appelant que ne le dirait une exception d'appel imbriquée.
La plupart du temps, vous ne vous souciez pas vraiment des exceptions non gérées. Parfois, vous devez vous assurer qu'il
finally
est appelé même si l'exception n'est pas gérée. Dans ce cas, vous l'attrapez vous-même et le relancez (voir cette réponse ):la source
Il semble que vous recherchez quelque chose comme ceci:
Veuillez noter que
finally
cela ne fait aucune exceptionla source
Vous n'avez pas de
catch
bloc, donc l'exception est toujours levée, ce qui bloque le retour.C'est faux, car le bloc finally serait exécuté, puis il y aurait une exception non interceptée.
finally
les blocs sont utilisés pour le nettoyage et ils n'attrapent pas l'exception. L'exception est levée avant le retour, par conséquent, le retour ne sera jamais atteint, car une exception est levée avant.Votre IDE est correct qu'il ne sera jamais atteint, car l'exception sera levée. Seuls les
catch
blocs peuvent attraper des exceptions.Lecture de la documentation ,
Cela montre clairement que le finally n'est pas destiné à intercepter l'exception, et vous auriez eu raison s'il y avait eu une
catch
instruction vide avant l'finally
instruction.la source
Lorsque l'exception est levée, la pile se déroule (l'exécution sort de la fonction) sans renvoyer de valeur, et tout bloc catch dans les cadres de pile au-dessus de la fonction intercepte l'exception à la place.
Par conséquent,
return false
ne s'exécutera jamais.Essayez de lever manuellement une exception pour comprendre le flux de contrôle:
la source
Sur votre code:
C'est la faille dans votre logique car le
finally
bloc n'attrapera pas l'exception et n'atteindra jamais la dernière instruction de retour.la source
La dernière instruction
return false
est inaccessible, car le bloc try n'a pas unecatch
partie qui gérerait l'exception, de sorte que l'exception est renvoyée après lefinally
bloc et l'exécution n'atteint jamais la dernière instruction.la source
Vous avez deux chemins de retour dans votre code, dont le second est inaccessible à cause du premier. La dernière instruction de votre
try
blocreturn returnValue == 1;
fournit votre retour normal, vous ne pouvez donc jamais atteindre lereturn false;
à la fin du bloc de méthode.FWIW, l'ordre d'exection lié au
finally
bloc est: l'expression fournissant la valeur de retour dans le bloc try sera évaluée en premier, puis le bloc finally sera exécuté, puis la valeur d'expression calculée sera retournée (à l'intérieur du bloc try).Concernant le flux sur exception ... sans a
catch
, lefinally
sera exécuté sur exception avant que l'exception ne soit ensuite renvoyée hors de la méthode; il n'y a pas de chemin de «retour».la source