J'ai vu certains programmeurs utiliser ceci:
foreach (var item in items)
{
if (item.Field != null)
continue;
if (item.State != ItemStates.Deleted)
continue;
// code
}
au lieu de celui que j'utiliserais normalement:
foreach (var item in items.Where(i => i.Field != null && i.State != ItemStates.Deleted))
{
// code
}
J'ai même vu une combinaison des deux. J'aime vraiment la lisibilité avec «continuer», en particulier avec des conditions plus complexes. Y a-t-il même une différence de performances? Avec une requête de base de données, je suppose qu'il y en aurait. Et les listes régulières?
c#
readability
loops
filtering
Paprik
la source
la source
Réponses:
Je considérerais cela comme un endroit approprié pour utiliser la séparation commande / requête . Par exemple:
Cela vous permet également de donner un bon nom auto-documenté au résultat de la requête. Il vous aide également à voir les opportunités de refactoring, car il est beaucoup plus facile de refactoriser du code qui interroge uniquement des données ou ne mute que des données que du code mixte qui essaie de faire les deux.
Lors du débogage, vous pouvez interrompre avant
foreach
de vérifier rapidement si le contenu de lavalidItems
résolution correspond à ce que vous attendez. Vous n'avez pas à entrer dans le lambda, sauf si vous en avez besoin. Si vous devez entrer dans le lambda, je suggère de le factoriser dans une fonction distincte, puis de le parcourir à la place.Y a-t-il une différence de performances? Si la requête est soutenue par une base de données, la version LINQ peut s'exécuter plus rapidement, car la requête SQL peut être plus efficace. S'il s'agit de LINQ to Objects, vous ne verrez aucune différence réelle de performances. Comme toujours, profilez votre code et corrigez les goulots d'étranglement qui sont réellement signalés, plutôt que d'essayer de prévoir les optimisations à l'avance.
la source
IEnumerable
estforeach
uniquement piloté par la boucle.Where
lambda et le corps de la boucle (si le lambda renvoie vrai) une fois par élément.Bien sûr, il existe une différence de performances, ce qui
.Where()
entraîne un appel délégué pour chaque élément. Cependant, je ne me soucierais pas du tout des performances:Les cycles d'horloge utilisés pour appeler un délégué sont négligeables par rapport aux cycles d'horloge utilisés par le reste du code qui itère sur la collection et vérifie les conditions.
La pénalité de performance d'invoquer un délégué est de l'ordre de quelques cycles d'horloge, et heureusement, nous avons longtemps dépassé les jours où nous devions nous soucier des cycles d'horloge individuels.
Si pour une raison quelconque, les performances sont vraiment importantes pour vous au niveau du cycle d'horloge, utilisez
List<Item>
plutôt à la place deIList<Item>
, afin que le compilateur puisse utiliser des appels directs (et inlinables) au lieu d'appels virtuels, et pour que l'itérateur deList<T>
, qui est en fait astruct
, ne doit pas être encadré. Mais c'est vraiment des trucs insignifiants.Une requête de base de données est une situation différente, car il y a (au moins en théorie) une possibilité d'envoyer le filtre au SGBDR, améliorant ainsi considérablement les performances: seules les lignes correspondantes feront le trajet du SGBDR vers votre programme. Mais pour cela, je pense que vous devriez utiliser linq, je ne pense pas que cette expression puisse être envoyée au SGBDR tel quel.
Vous verrez vraiment les avantages du
if(x) continue;
moment où vous devez déboguer ce code: le passage simple surif()
s etcontinue
s fonctionne bien; une seule étape dans le délégué de filtrage est une douleur.la source
if(x) continue;
..Where
n'est invoqué qu'une seule fois. Ce qui est invoqué à chaque itération est le délégué du filtre (etMoveNext
etCurrent
sur le recenseur, quand ils ne sont pas optimisés out).Where
n'est invoqué qu'une seule fois. A corrigé.