Souvent, je veux vérifier si une valeur fournie correspond à une dans une liste (par exemple lors de la validation):
if (!acceptedValues.Any(v => v == someValue))
{
// exception logic
}
Récemment, j'ai remarqué que ReSharper me demandait de simplifier ces requêtes pour:
if (acceptedValues.All(v => v != someValue))
{
// exception logic
}
Évidemment, c'est logiquement identique, peut-être un peu plus lisible (si vous avez fait beaucoup de mathématiques), ma question est: cela entraîne-t-il un impact sur les performances?
On dirait que ça devrait (c'est-à-dire .Any()
que ça sonne comme des courts-circuits, alors .All()
que ça ne sonne pas), mais je n'ai rien pour le prouver. Quelqu'un a-t-il une connaissance plus approfondie de savoir si les requêtes vont résoudre le même problème, ou si ReSharper me induit en erreur?
if (!sequence.Any(v => v == true))
. Si vous souhaitez continuer que si tout est conforme à une certaine spécification:if (sequence.All(v => v < 10))
.Réponses:
Implémentation de
All
selon ILSpy (comme en fait je suis allé voir, plutôt que "bien, cette méthode fonctionne un peu comme ..." Je pourrais le faire si nous discutions de la théorie plutôt que de l'impact).Implémentation de
Any
selon ILSpy:Bien sûr, il pourrait y avoir une différence subtile dans l'IL produit. Mais non, non. L'IL est à peu près le même, mais pour l'inversion évidente du retour de true sur la correspondance de prédicat contre le retour de false sur la non-correspondance de prédicat.
Il s'agit bien sûr de linq-for-objects. Il est possible qu'un autre fournisseur linq en traite un bien mieux que l'autre, mais si tel était le cas, il est à peu près aléatoire lequel a obtenu la mise en œuvre la plus optimale.
Il semblerait que la règle se résume uniquement à quelqu'un qui
if(determineSomethingTrue)
se sent plus simple et plus lisible queif(!determineSomethingFalse)
. Et en toute honnêteté, je pense qu'ils ont un petit point en ce que je trouve souventif(!someTest)
déroutant * quand il existe un autre test de verbosité et de complexité égales qui reviendrait vrai pour la condition sur laquelle nous voulons agir. Pourtant, vraiment, je ne trouve personnellement rien à privilégier l'une par rapport à l'autre des deux alternatives que vous donnez, et je pencherais peut-être très légèrement vers la première si le prédicat était plus compliqué.* Pas déroutant comme dans Je ne comprends pas, mais déroutant comme dans Je m'inquiète qu'il y ait une raison subtile pour la décision que je ne comprends pas, et il faut quelques sauts mentaux pour réaliser que "non, ils ont juste décidé de faire de cette façon, attendez à quoi je cherchais encore ce bout de code? ... "
la source
Any
retournerafalse
et donc!Any
sera de retourtrue
, ils sont donc identiques.!test.Any(x => x.Key == 3 && x.Value == 1)
cette utilisationAll
esttest.All(x => !(x.Key == 3 && x.Value == 1))
(qui est en effet équivalent àtest.All(x => x.Key != 3 || x.Value != 1)
).Vous trouverez peut-être que ces méthodes d'extension rendent votre code plus lisible:
Maintenant, au lieu de votre original
Tu pourrais dire
la source
Les deux auraient des performances identiques, car les deux arrêtent l'énumération une fois le résultat déterminé -
Any()
sur le premier élément, le prédicat passé est évaluétrue
etAll()
sur le premier élément, le prédicat est évaluéfalse
.la source
All
courts-circuits sur le premier non-match, donc ce n'est pas un problème.Un domaine de subtilité est que
Est vrai. Tous les éléments de la séquence sont pairs.
Pour plus d'informations sur cette méthode, consultez la documentation d' Enumerable.All .
la source
bool allEven = !Enumerable.Empty<int>().Any(i => i % 2 != 0)
c'est vrai aussi.All()
détermine si tous les éléments d'une séquence satisfont une condition.Any()
détermine si un élément d'une séquence satisfait à la condition.la source
Selon ce lien
la source
Comme d'autres réponses l'ont bien couvert: ce n'est pas une question de performance, c'est une question de clarté.
Il existe un large soutien pour vos deux options:
Mais je pense que cela pourrait obtenir un soutien plus large :
Le simple fait de calculer le booléen (et de le nommer) avant d'annuler quoi que ce soit clarifie beaucoup cela dans mon esprit.
la source
Si vous jetez un œil à la source Enumerable, vous verrez que l'implémentation de
Any
etAll
est assez proche:Il n'y a aucun moyen qu'une méthode soit significativement plus rapide que l'autre car la seule différence réside dans une négation booléenne, donc préférez la lisibilité à une fausse performance.
la source