2009-06-05 8 views
1

Les expressions Lambda et Linq suivantes sont-elles équivalentes en termes de chemins d'exécution? Je suppose que je me demande si le Linq va fonctionner différemment parce qu'il va créer un IEnumerable avant de déterminer si l'énumération contient quelque chose alors que l'expression lambda s'arrêtera sur le premier chiffre trouvé.Les expressions Lambda et Linq suivantes sont-elles équivalentes?

var x = valueToMatch 
    .Any(c => Char.IsDigit(c)); 

var y = (from c in valueToMatch 
     select c).Any(c => Char.IsDigit(c)); here 

Thx! Joel

Répondre

3

Il fonctionnera différemment, mais pas de façon considérable. Si vous utilisez le MSIL Disassembler, vous verrez une sortie légèrement différente pour la première expression et la seconde, même si les optimisations sont activées. Vous pouvez également le regarder en utilisant un Reflector (ce qui est un peu plus facile à lire).

La deuxième version passera essentiellement chaque élément par quelque chose comme:

[CompilerGenerated] 
private static char <Match2>b__2(char c) 
{ 
    return c; 
} 

avant qu'il exécute l'expression Tout (c => Char.IsDigit (c)). Donc, il y a effectivement une différence.

Cependant, la différence est très faible à mon avis. Test d'une liste de 10 000 caractères bouclés sur 10 000 000 avec chaque méthode le premier horloge environ ~ 125 ms alors que la seconde méthode prend ~ 185 ms.

+1

vous pouvez également utiliser LINQPad pour voir le IL . À mon humble avis le «de c dans valueToMatch select c» est assez redondant dans ce cas – dplante

+0

En effet, je pense que c'était plus d'un exercice de pensée «ce qui se passe», au moins pour moi. – rmoore

1

Ils sont à peu près équivalents. Le compilateur optimisera probablement le select et les deux seront identiques à 100%. À tout moment, Linq est évalué paresseux, de sorte que valueToMatch sera énuméré exactement le même montant dans les deux cas.

+2

Le compilateur n'optimisera PAS la sélection, et il y a une bonne raison à cela. Voir mon article sur le sujet: http://blogs.msdn.com/ericlippert/archive/2008/05/12/trivial-projections-are-usually-optimized-away.aspx –

0

Pour les expressions de requête, cela représente la identity function:

from c in valueToMatch select c 

Cela signifie le résultat de l'expression sera exactement égale à l'entrée, matchToValue. Par conséquent, les exemples que vous avez fournis sont sémantiquement équivalents.

Dans le cas d'une sélection non-identité tels que:

from c in valueToMatch select c + ";" 

un IEnumerable<char> est créé, quand énumérés, consommera le contenu de valueToMatch et de les modifier.

Cet appel:

(from c in valueToMatch select c + ";").Any(c => Char.IsDigit(c)) 

la requête interne énumère jusqu'à ce qu'il trouve une correspondance. Comme vous pouvez le voir, peu importe la requête source, elle ne sera pas exécutée avant l'appel à Any. L'instance IEnumerable<char> représente la possibilité d'exécuter une requête, pas une requête qui a déjà été exécutée. Ce concept est connu comme deferred execution.

Questions connexes