107 votes

C # - Quel est le meilleur moyen de modifier une liste dans une boucle 'foreach'?

Une nouvelle fonctionnalité de C# / .NET 4.0 est que vous pouvez changer votre énumérable en foreach sans exception. Paul Jackson de l'entrée de blog Intéressant à Effet de Simultanéité: Suppression d'Éléments d'une Collection lors de l'Énumération pour plus d'informations sur ce changement.

Quelle est la meilleure façon de faire les choses suivantes?

foreach(var item in Enumerable)
{
    foreach(var item2 in item.Enumerable)
    {
        item.Add(new item2)
    }
}

Habituellement j'utilise un IList comme un cache/tampon jusqu'à la fin de l' foreach, mais est-il une meilleure façon?

94voto

Rik Points 12802

La collection utilisée dans le foreach est immuable. C'est très bien de par leur conception.

Comme il est dit sur MSDN:

L'instruction foreach est utilisé pour parcourir la collection pour obtenir les informations que vous voulez, mais peut pas être utilisé pour ajouter ou supprimer des éléments à partir de la source de collecte afin d'éviter imprévisible des effets secondaires. Si vous besoin d'ajouter ou de supprimer des éléments de la source collecte, à l'utilisation d'une boucle for.

Le poste dans le lien fourni par Poko indique que cela est permis dans la nouvelle concurrente de collections.

15voto

tvanfosson Points 268301

Faites une copie de l'énumération, en utilisant une méthode d'extension IEnumerable dans ce cas, et énumérez-la par-dessus. Cela ajouterait une copie de chaque élément de chaque énumérable interne à cette énumération.

 foreach(var item in Enumerable)
{
    foreach(var item2 in item.Enumerable.ToList())
    {
        item.Add(item2)
    }
}
 

8voto

eulerfx Points 16320

Comme mentionné, mais avec un exemple de code:

 foreach(var item in collection.ToArray())
    collection.Add(new Item...);
 

5voto

Nippysaurus Points 6809

Vous devriez vraiment utiliser for () au lieu de foreach () dans ce cas.

3voto

Anton Gogolev Points 59794

Voici comment procéder (solution rapide et rapide. Si vous avez vraiment besoin de ce type de comportement, vous devez soit revoir votre conception, soit remplacer tous les membres IList<T> et agréger la liste des sources):

 using System;
using System.Collections.Generic;

namespace ConsoleApplication3
{
    public class ModifiableList<T> : List<T>
    {
        private readonly IList<T> pendingAdditions = new List<T>();
        private int activeEnumerators = 0;

        public ModifiableList(IEnumerable<T> collection) : base(collection)
        {
        }

        public ModifiableList()
        {
        }

        public new void Add(T t)
        {
            if(activeEnumerators == 0)
                base.Add(t);
            else
                pendingAdditions.Add(t);
        }

        public new IEnumerator<T> GetEnumerator()
        {
            ++activeEnumerators;

            foreach(T t in ((IList<T>)this))
                yield return t;

            --activeEnumerators;

            AddRange(pendingAdditions);
            pendingAdditions.Clear();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            ModifiableList<int> ints = new ModifiableList<int>(new int[] { 2, 4, 6, 8 });

            foreach(int i in ints)
                ints.Add(i * 2);

            foreach(int i in ints)
                Console.WriteLine(i * 2);
        }
    }
}
 

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