Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Editing Enumerator within foreach loop (well, not really)

4.93/5 (4 votes)
26 Jan 2011CPOL 8.6K  
A simple way to edit a list or collection which is iterated in a foreach loop
Recently, I had to process a Collection of class objects after a split over some properties. I did the split through a relatively simple Select and Distinct extension methods. The next task was to split the result again in batches and process. I discovered this while doing that. The ToList extension method, supposedly, creates a deep copy of the IEnumerator returned by the LINQ expression. Following is a simple code to demonstrate.

class Animals
{
    public bool Herbivore { get; set; }

    public bool IsMammal { get; set; }

    public string CommonName { get; set; }
}

private static void SendBatches()
{
    Collection<Animals> animalCollection = new Collection<Animals>();

    animalCollection.Add(new Animals { Herbivore = true, IsMammal = true, CommonName = "Cow" });
    animalCollection.Add(new Animals { Herbivore = false, IsMammal = true, CommonName = "Cat" });
    animalCollection.Add(new Animals { Herbivore = false, IsMammal = true, CommonName = "Dog" });
    animalCollection.Add(new Animals { Herbivore = true, IsMammal = true, CommonName = "Lamb" });

    // Ignoring those weird mammals who lay eggs
    var herbivores = (from animal in animalCollection
                      where animal.Herbivore
                      select new { Name = animal.CommonName, LaysEggs = !animal.IsMammal });

    foreach (var herbivore in herbivores)
    {
        if (herbivore.Name.StartsWith("C", StringComparison.InvariantCultureIgnoreCase))
        {
            animalCollection.Remove(animalCollection.Where(x => string.Compare(x.CommonName, herbivore.Name, true) == 0).First());
        }
    }
}


As expected, the foreach will fail at the second iteration since we have changed the Enumerator. But, if we change the LINQ expression to the following, it works:

C#
var herbivores = (from animal in animalCollection
                              where animal.Herbivore
                              select new { Name = animal.CommonName, LaysEggs = !animal.IsMammal }).ToList();


Even ToArray gives the same behavior.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)