Imaginez le code suivant:
void DoThis()
{
if (!isValid) return;
DoThat();
}
void DoThat() {
Console.WriteLine("DoThat()");
}
Est-il correct d'utiliser un retour dans une méthode void? At-il une pénalité de performance? Ou il serait préférable d'écrire un code comme celui-ci:
void DoThis()
{
if (isValid)
{
DoThat();
}
}
Un retour dans une méthode void n'est pas mauvais, est une pratique courante pour inverser les instructions if
pour réduire l'imbrication .
Et avoir moins d'imbrication sur vos méthodes améliore la lisibilité et la maintenabilité du code.
En fait, si vous avez une méthode void sans aucune instruction return, le compilateur générera toujours une instruction ret à la fin de celle-ci.
Il existe une autre bonne raison d'utiliser des gardes (par opposition au code imbriqué): si un autre programmeur ajoute du code à votre fonction, il travaille dans un environnement plus sûr.
Considérer:
void MyFunc(object obj)
{
if (obj != null)
{
obj.DoSomething();
}
}
contre:
void MyFunc(object obj)
{
if (obj == null)
return;
obj.DoSomething();
}
Maintenant, imaginez qu'un autre programmeur ajoute la ligne: obj.DoSomethingElse ();
void MyFunc(object obj)
{
if (obj != null)
{
obj.DoSomething();
}
obj.DoSomethingElse();
}
void MyFunc(object obj)
{
if (obj == null)
return;
obj.DoSomething();
obj.DoSomethingElse();
}
Évidemment, c'est un cas simpliste, mais le programmeur a ajouté un plantage au programme dans la première instance (code imbriqué). Dans le deuxième exemple (sortie anticipée avec les gardes), une fois que vous avez dépassé la garde, votre code est à l'abri de l'utilisation involontaire d'une référence nulle.
Bien sûr, un bon programmeur ne fait pas d'erreurs comme ça (souvent). Mais mieux vaut prévenir que guérir - nous pouvons écrire le code d'une manière qui élimine entièrement cette source potentielle d'erreurs. L'imbrication ajoute de la complexité. Les meilleures pratiques recommandent donc de refactoriser le code pour réduire l'imbrication.
Mauvaise pratique ??? En aucune façon. En fait, il est toujours préférable de gérer les validations en revenant de la méthode au plus tôt si les validations échouent. Sinon, cela entraînerait une énorme quantité d'if et d'eles imbriqués. Une résiliation anticipée améliore la lisibilité du code.
Vérifiez également les réponses à une question similaire: Dois-je utiliser l'instruction return/continue au lieu de if-else?
Ce n'est pas une mauvaise pratique (pour toutes les raisons déjà indiquées). Cependant, plus vous avez de retours dans une méthode, plus elle devrait être divisée en méthodes logiques plus petites.
Le premier exemple utilise une instruction guard. De Wikipedia :
En programmation informatique, un gardien est une expression booléenne qui doit être évaluée comme vraie si l'exécution du programme doit se poursuivre dans la branche en question.
Je pense qu'avoir un tas de gardes au sommet d'une méthode est une façon parfaitement compréhensible de programmer. Cela revient à dire "n'exécutez pas cette méthode si l'une d'entre elles est vraie".
Donc, en général, il aimerait ceci:
void DoThis()
{
if (guard1) return;
if (guard2) return;
...
if (guardN) return;
DoThat();
}
Je pense que c'est beaucoup plus lisible alors:
void DoThis()
{
if (guard1 && guard2 && guard3)
{
DoThat();
}
}
Il n'y a pas de pénalité de performance, mais le deuxième morceau de code est plus lisible et donc plus facile à entretenir.
C'est tout à fait correct et sans "pénalité de performance", mais n'écrivez jamais de déclaration "si" sans crochets.
Toujours
if( foo ){
return;
}
C'est beaucoup plus lisible; et vous ne supposerez jamais accidentellement que certaines parties du code se trouvent dans cette déclaration alors qu'elles ne le sont pas.
Dans ce cas, votre deuxième exemple est un meilleur code, mais cela n'a rien à voir avec le retour d'une fonction void, c'est simplement parce que le deuxième code est plus direct. Mais le retour d'une fonction vide est tout à fait correct.
Je vais être en désaccord avec vous tous les jeunes whippersnappers sur celui-ci.
Utiliser le retour au milieu d'une méthode, nulle ou non, est une très mauvaise pratique, pour des raisons qui ont été articulées très clairement, il y a près de quarante ans, par le regretté Edsger W. Dijkstra, à commencer par la fameuse "déclaration GOTO considérée comme nuisible". ", et en continuant dans" Structured Programming ", par Dahl, Dijkstra et Hoare.
La règle de base est que chaque structure de contrôle et chaque module doivent avoir exactement une entrée et une sortie. Un retour explicite au milieu du module enfreint cette règle et rend beaucoup plus difficile de raisonner sur l'état du programme, ce qui rend à son tour beaucoup plus difficile de dire si le programme est correct ou non (ce qui est une propriété beaucoup plus forte). que "si cela semble fonctionner ou non").
La "déclaration GOTO considérée comme nuisible" et la "programmation structurée" ont donné le coup d'envoi à la révolution de la "programmation structurée" des années 1970. Ces deux éléments sont les raisons pour lesquelles nous avons if-then-else, while-do et d'autres constructions de contrôle explicites aujourd'hui, et pourquoi les instructions GOTO dans les langages de haut niveau sont sur la liste des espèces en voie de disparition. (Mon opinion personnelle est qu'ils doivent figurer sur la liste des espèces disparues.)
Il convient de noter que le Message Flow Modulator, le premier logiciel militaire qui a JAMAIS réussi les tests d'acceptation du premier coup, sans aucune déviation, aucune dérogation ou "oui, mais" verbiage, a été écrit dans une langue qui n'avait même pas une instruction GOTO.
Il convient également de mentionner que Nicklaus Wirth a changé la sémantique de l'instruction RETURN dans Oberon-07, la dernière version du langage de programmation Oberon, ce qui en fait un élément de fin de la déclaration d'une procédure typée (c'est-à-dire, une fonction), plutôt qu'un instruction exécutable dans le corps de la fonction. Son explication du changement a dit qu'il l'a fait précisément parce que le formulaire précédent ÉTAIT une violation du principe à une sortie de la programmation structurée.