2017-05-18 1 views
3
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> source, Action<T> action) 
    { 
     foreach (var element in source) action(element); 
     return source; 
    } 

Le code ci-dessus me donne un avertissement que la source est potentiellement itérée plusieurs fois, mais est-ce vraiment? Il est répété une fois dans l'instruction foreach, mais comment l'instruction return l'a-t-elle réitérée?Y a-t-il vraiment plusieurs itérations d'un IEnumerable dans ce code?

+6

Eh bien dans un certain sens, parce que vous le renvoyez à l'appelant et ce que l'appelant peut faire avec 'IEnumerable'? Seulement l'énumérer à nouveau. Comme dans myList.ForEach (c => DoStuff (c)). ToArray() ' Evk

+0

Est-il possible d'avoir une exécution différée sur des élémenents dans un énumérable? – Mardoxx

Répondre

4

Le retour ne réitère pas l'énumérable. Mais vous le retournez, et puisque la seule façon dont vous pourriez faire quelque chose avec ce résultat est de l'itérer ailleurs, cet avertissement est donné. Pourquoi le retourner si vous n'allez pas l'itérer plus tard?

+0

Oui, il sera ré-itéré. Je voulais une version Linq de ForEach afin que je puisse faire des choses comme list.ForEach (x => x.Number ++). Où (x => x.Number> 3) .Etc ... –

+1

Utilisez simplement select. Par exemple: liste.Sélectionnez (x => x ++). Où (x => x> 3) –

1

Dans le code actuel, vous montrez qu'il n'y a qu'une seule itération. Il est fort possible que vous l'énumériez encore ailleurs, puisque le même énumérable est renvoyé. C'est ce que l'avertissement vous dit.

Ma préférence personnelle serait de changer le type de retour du ForEach en void, et d'ajouter un second qui renvoie le résultat d'un Func<T, R>.

Alors:

public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) 
{ 
    foreach (var element in source) 
     action(element); 
} 

Et:

public static IEnumerable<R> ForEach<T, R>(this IEnumerable<T> source, Func<T, R> action) 
{ 
    foreach (var element in source) 
     yield return action(element); 
} 

De cette façon, vous ne réutilisez accidentellement le même dénombrable et vous faites ce paresseux: il ne sera pas exécuté avant d'appeler réellement la dénombrable .

+0

La seconde devrait fonctionner; mais, il pourrait "éventuellement" violer les contraintes de type OP. –

+0

Pourquoi est-ce? @ AlyEl-Haddad –

+0

Parce que dans sa méthode, il garantit que le type du 'IEnumerable 'retourné sera le même que celui de la source. Ici, le type de 'IEnumerable' retourné 'peut différer selon le paramètre de la fonction; et c'est pourquoi j'ai dit "peut-être". @Patrick Hofman –