Pour un développeur, la lecture de code fait partie d’un régime sain et équilibré afin de pouvoir apprendre de nouvelles façons de faire et d’améliorer sa technique au clavier. Ce n’est pas compliqué: c’est en regardant qu’on apprend!
Or, lors de l’écriture de L’histoire d’un rubberducking et ASP.NET MVC, je me suis adonné sur le repository d’ASP.NET 5 sur GitHub. J’étais à la recherche de la façon qu’ASP.NET s’y prenait pour faire le mappage entre les données arrivant d’une requête HTTP et un type utilisé comme modèle.
Dans mes recherches, il y a un petit bout de code qui a attiré mon attention. Surtout parce qu’il était composé d’une façon que je n’avais jamais vue auparavant.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
foreach (ModelError error in modelState.Errors.Where(err => String.IsNullOrEmpty(err.ErrorMessage) && err.Exception != null).ToList()) | |
{ | |
for (Exception exception = error.Exception; exception != null; exception = exception.InnerException) | |
{ | |
// We only consider "known" type of exception and do not make too aggressive changes here | |
if (exception is FormatException || exception is OverflowException) | |
{ | |
string displayName = propertyMetadata.GetDisplayName(); | |
string errorMessageTemplate = GetValueInvalidResource(controllerContext); | |
string errorMessage = String.Format(CultureInfo.CurrentCulture, errorMessageTemplate, modelState.Value.AttemptedValue, displayName); | |
modelState.Errors.Remove(error); | |
modelState.Errors.Add(errorMessage); | |
break; | |
} | |
} | |
} |
Seriez-vous en mesure de deviner de quoi il est question, au juste? Non? Vous donnez votre langue aux chats? D’accord. Jetez un coup d’oeil à la ligne 4 de l’exemple de code.
for (Exception exception = error.Exception; exception != null; exception = exception.InnerException)
Ce n’est pas une boucle for sous sa forme classique, n’est-ce pas?
À la première lecture, j’étais un peu confus sur ce que devait accomplir cette boucle. Après quelques lectures et une exécution dans une petite classe maison, j’ai compris. En fait, c’est un bout de code assez élégant pour deux raisons.
- Il s’agit d’une façon de faire de la récursion tout un bloc d’exécution « classique ».
- D’un point de vue de la clarté, si vous savez que vous allez vouloir court-circuiter l’exécution d’une boucle avec un break, je crois qu’il est effectivement préférable d’utiliser une boucle sous cette forme.
Dans le passé, par paresse, lorsque j’avais besoin d’itérer une collection, je passais par foreach. De plus, j’aurais eu recours à de la récursion pour traverser la pile d’erreurs imbriquées.
Après coup, je crois qu’il y a effectivement une différence fondamentale entre le for et le foreach. Les deux permettent, en effet, d’itérer une collection d’éléments. Par contre, au niveau de la syntaxe, un for a une portée bien délimitée. Il faut lui indiquer à quel moment s’arrêter et comment procéder pour l’itération. Tandis que, pour le foreach, il traverse une collection du début à la fin.
Alors, à la lumière de ceci, pourquoi devrais-je utiliser une boucle foreach alors que je vais devoir l’interrompre dans le parcours de la collection selon une condition donnée? À présent, sachant que cette technique existe, je serai possiblement plus attentif à tenter de l’utiliser dans mon quotidien.
Au niveau de la revue de code, je crois que cela peut aider à rendre le code plus clair et l’intention mieux définie.
3 réflexions sur “Une revue de code autour de l’utilisation d’une boucle for”