2009-10-04 9 views
9

Si j'écris un statment foreach en C#:foreach en C# recalcul

foreach(String a in veryComplicatedFunction()) 
{ 

} 

aura-t-il calculer veryComplicatedFunction chaque itération ou une seule fois, et le stocker quelque part?

+19

Vous pourriez ajouter un Debug.WriteLine() à veryComplicatedFunction() et le découvrir par vous-même! – Chris

Répondre

38

Votre question est posée par l'article 8.8.4 de la spécification, qui stipule:


Les étapes ci-dessus, en cas de succès, produire sans ambiguïté une collection type C, type E recenseur et élément de type T. Une déclaration foreach du formulaire

foreach (V v in x) embedded-statement 

est ensuite étendu à:

{ 
    E e = ((C)(x)).GetEnumerator(); 
    try { 
     V v; 
     while (e.MoveNext()) { 
      v = (V)(T)e.Current; 
      embedded-statement 
     } 
    } 
    finally { 
     … // Dispose e 
    } 
} 

Comme vous pouvez le voir, l'expansion de l'expression x est évaluée uniquement une fois.

18

Il ne calcule une fois

5

veryComplicatedFunction retourne probablement IEnumerable<string>, ce qui devrait signifier que celui-ci sont effectuées de calculs qu'une seule fois et les cours d'eau ses résultats d'une certaine façon. Cependant, sans voir la méthode actuelle, il n'y a aucun moyen de garantir ce qu'il fait. Ce qui est garanti, c'est que veryComplicatedFunction est seulement appelée une fois, ce que le foreach fait est de parcourir les retours d'une méthode.

1

Il devrait le calculer juste une fois. En remarque, la fonction verycomplicated() doit renvoyer un IEnumerable ou IEnumerable<T> ou tout objet ayant une méthode publique GetEnumerator().

+8

En fait, votre note de côté n'est pas correcte. Tant qu'il renvoie un objet qui a une méthode GetEnumerator qui ne prend aucun paramètre et retourne un IEnumerator ou une dérivation de celui-ci, il fonctionnera avec l'instruction foreach. La classe elle-même n'a pas besoin d'implémenter IEnumerable. –

+0

Geez vous avez raison. Je vais corriger ma réponse. J'avais l'impression que pour faire un foreach le type sous-jacent doit être un IEnumerable. On dirait que le compilateur est content tant qu'il existe une définition publique de GetEnumerator() disponible. Intéressant ... –

+0

Un exemple de dactylographie en.net ;-) (Je pense qu'il n'y en a pas encore d'autres) –

6

Cela dépend de ce que vous entendez par une fois. Si vous avez une méthode comme ce qui suit:

public static IEnumerable<int> veryComplicatedFunction() 
{ 
    List<string> l = new List<string> { "1", "2", "3" }; 
    foreach (var item in l) 
    { 
     yield return item; 
    } 
} 

contrôle serait retourné à la méthode d'appel veryComplicatedFunction après chaque rendement. Donc, s'ils partageaient la liste l, vous pourriez avoir des résultats étranges. Un moyen sûr de supprimer ce genre de problème serait d'appeler l'extension ToArray sur la fonction veryComplicatedFunction.

0

Si elle le calculait à chaque fois, cela pourrait causer un monde de douleur si votre fonction était basée sur quelque chose de dynamique comme l'heure actuelle. Il devrait le calculer une fois.