455 votes

Pourquoi n'est-il pas un ForEach de la méthode d'extension sur l'interface IEnumerable?

Inspiré par une autre question à poser des questions sur le manque Zip de la fonction:

Pourquoi n'est-il pas ForEach méthode d'extension dans l'Énumération de la classe? Ou n'importe où? La seule classe qui obtient un ForEach méthode List<>. Pourquoi est-ce qu'il manque (de performance)?

222voto

Coincoin Points 12823

Il y a déjà une instruction foreach inclus dans la langue qui fait le travail la plupart du temps.

J'avais hate de voir les suivants:

list.ForEach( item =>
{
    item.DoSomething();
} );

Au lieu de:

foreach(Item item in list)
{
     item.DoSomething();
}

Ce dernier est plus clair et plus facile à lire dans la plupart des situation, bien que peut-être un peu plus long à taper.

Cependant, je dois admettre que j'ai changé ma position sur cette question; un ForEach() la méthode d'extension serait en effet utile dans certaines situations.

Voici les principales différences entre la déclaration et la méthode:

  • La vérification du Type: foreach est fait au moment de l'exécution, ForEach() est au moment de la compilation (Plus Grand!)
  • La syntaxe pour appeler un délégué est en effet beaucoup plus simple: les objets.ForEach(DoSomething);
  • ForEach() pourrait être enchaîné: bien que mal/l'utilité d'une telle fonctionnalité est ouvert à la discussion.

Ceux sont tous des grands points faite par beaucoup de gens ici, et je peux voir pourquoi les gens sont absents de la fonction. Je n'aurais pas l'esprit de Microsoft à l'ajout d'un standard ForEach méthode dans le cadre de l'itération.

87voto

aku Points 54867

ForEach méthode a été ajoutée avant de LINQ. Si vous ajoutez ForEach extension, il ne sera jamais appelé à la Liste des cas en raison de l'extension des méthodes de contraintes. Je pense que la raison pour laquelle il n'a pas été ajoutée n'est pas de l'interférence avec l'existant.

Toutefois, si vous manquez vraiment de ce petit nice de la fonction, vous pouvez introduire votre propre version

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

58voto

Jay Bazuzi Points 20462

Vous pourriez écrire cette méthode d'extension:

// Possibly call this "Do"
IEnumerable<T> Apply<T> (this IEnumerable<T> source, Action<T> action)
{
    foreach (var e in source)
    {
        action(e);
        yield return e;
    }
}

Pros

Permet le chaînage:

MySequence
    .Apply(...)
    .Apply(...)
    .Apply(...);

Cons

Il ne sera pas réellement faire quelque chose jusqu'à ce que vous faire quelque chose pour forcer l'itération. Pour cette raison, il ne devrait pas être appelé .ForEach(). Vous pouvez écrire .ToList() à la fin, ou vous pourriez écrire cette méthode d'extension, trop:

// possibly call this "Realize"
IEnumerable<T> Done<T> (this IEnumerable<T> source)
{
    foreach (var e in source)
    {
        // do nothing
        ;
    }

    return source;
}

C'est peut-être trop importante d'un départ de l'expédition C# bibliothèques; les lecteurs qui ne sont pas familiers avec vos méthodes d'extension ne savez pas quoi faire de votre code.

42voto

mancaus Points 2266

La discussion ici donne la réponse.

Fondamentalement, la décision a été prise de conserver les méthodes d'extension fonctionnellement "pure". Un ForEach encouragerait les effets secondaires lors de l'utilisation de l'Énumération des méthodes d'extension, ce qui n'était pas l'intention.

22voto

Chris Zwiryk Points 1162

Alors que je suis d'accord qu'il est préférable d'utiliser le haut- foreach construire dans la plupart des cas, je trouve l'utilisation de cette variation sur le ForEach<> extension à être un peu plus agréable que d'avoir à gérer l'index dans un foreach moi-même:

public static int ForEach<T>(this IEnumerable<T> list, Action<int, T> action)
{
    if (action == null) throw new ArgumentNullException("action");

    var index = 0;

    foreach (var elem in list)
        action(index++, elem);

    return index;
}

Exemple

var people = new[] { "Moe", "Curly", "Larry" };
people.ForEach((i, p) => Console.WriteLine("Person #{0} is {1}", i, p));

Vous donnerait:

Person #0 is Moe
Person #1 is Curly
Person #2 is Larry

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X