Bellow est ma réponse mais aussi noter que Jon Skeet en a parlé aujourd'hui sur son blog et sur le fait qu'il ne soit pas totalement d'accord avec le sens MSDN de "Lazy" car MSDN n'est pas vraiment clair de ce paresseux exactement dire quand ils l'utilisent dans Just how lazy are you ? son poste faire pour une lecture intéressante. En outre WikipediaWikipedia en outre supposer que trois règles doivent être conservées pour évaluation paresseux et troisième point n'est pas respectée dans MSDN signifiant que l'expression sera évaluée plusieurs fois si GetEnumerator
est appelée à nouveau (par la spécification Reset n'est pas implémentée sur énumérateur objets générés à l'aide du mot clé yield
et la plupart des LINQ utiliser actuellement)
Considérant une fonction
int Computation(int index)
exécution immédiate
IEnumerable<int> GetComputation(int maxIndex)
{
var result = new int[maxIndex];
for(int i = 0; i < maxIndex; i++)
{
result[i] = Computation(i);
}
return result;
}
- Lorsque la fonction est appelée
Computation
est exécutée maxIndex
fois
GetEnumerator
retourne une nouvelle instance de ne rien faire recenseur plus.
- Chaque appel à
MoveNext
met la valeur stockée dans la cellule Array suivante dans le membre Current
du IEnumerator
et c'est tout.
Coût: Big avance, petit lors de l'énumération (seulement une copie)
différée mais l'exécution désireux
IEnumerable<int> GetComputation(int maxIndex)
{
var result = new int[maxIndex];
for(int i = 0; i < maxIndex; i++)
{
result[i] = Computation(i);
}
foreach(var value in result)
{
yield return value;
}
}
- Lorsque la fonction est appelée une instance d'une classe générée automatique (appelé "objet énumérable" dans la spécification)
IEnumerable
est créé et une copie de l'argument (maxIndex
) y est stockée.
GetEnumerator
renvoie une nouvelle instance de l'énumérateur qui ne fait rien de plus.
- Le premier appel à
MoveNext
exécute maxIndex fois la méthode de calcul, stocker le résultat dans un tableau et Current
retournera la première valeur.
- Chaque appel ultérieur au
MoveNext
mettra une valeur Current
stockée dans le tableau.
Coût: rien d'avance, Big quand le début de l'énumération, Petit cours de l'énumération (seulement une copie)
reportés et exécution paresseux
IEnumerable<int> GetComputation(int maxIndex)
{
for(int i = 0; i < maxIndex; i++)
{
yield return Computation(i);
}
}
- Lorsque la fonction est appelée même chose que le cas d'exécution paresseux se produit.
GetEnumerator
renvoie une nouvelle instance de l'énumérateur ne faisant rien de plus.
- Chaque appel à
MoveNext
exécute une fois le code Computation
, placez la valeur dans Current
et laissez l'appelant agir immédiatement sur le résultat.
La plupart des linq utilisent une exécution différée et paresseuse, mais certaines fonctions ne peuvent pas être similaires au tri.
Coût: rien d'avance, modéré pendant l'énumération (le calcul est exécuté là)
Pour résumer
- immédiate signifie que le calcul/l'exécution se fait dans la fonction et a terminé une fois la fonction revenir. (Entièrement eager évaluation comme la plupart du code C# ne)
- différés/Eager signifie que la plupart des travaux seront effectués sur la première
MoveNext
ou lorsque l'instance IEnumerator
est créé (Pour IEnumerable
il est quand GetEnumerator
est appelé)
- différés/Lazy signifie que le travail sera effectué chaque fois que
MoveNext
est appelé mais rien avant.
Parallel LINQ-t-il un peu différemment que le calcul pourrait être considéré comme différé/Lazy du point de vue de l'appelant, mais en interne le calcul d'un certain nombre d'éléments commencent en parallèle dès que l'énumération commence. Le résultat est que si la prochaine valeur est déjà là, vous l'obtenez immédiatement, mais sinon vous devrez l'attendre.
Ho Joel Martinez, merci beaucoup pour votre réponse. –
Pas si vite! Cela ne fonctionnera pas pour les données relationnelles. –
Qu'est-ce que les données relationnelles ont à faire avec l'évaluation avide d'un ienumerable? même si l'ienumerable est contre quelque chose comme linq2sql ou ef, il va itérer tous les enregistrements en mémoire (ce qui vous permet de fermer la connexion db tôt). –