1

I noticed an issue with enumerating over a collection that was a result of a .Select<T>() I can enumerate over it, and modify each item in the collection. When I look at the collection after the enumeration is completed each item is left un-modified.

public class FooModel
{
    public Guid? Id { get; set; }
}

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        IEnumerable<FooModel> foos = Enumerable.Range(0, 100)
            .Select(m => new FooModel());

        foreach(FooModel f in foos)
        {
            f.Id = Guid.NewGuid();
        }

        Assert.IsTrue(foos.All(foo => foo.Id.HasValue));
    }
}

If I append .ToList() or .ToArray() to execute the enumerable, then it modifies the items within the collection.

I understand that the IEnumerable isn't executed after the .Select<T>, but when the foreach runs it creates an enumerator and executes the IEnumerable on the foo local field. Why isn't it referencing the same object that the Select<T> creates?

I've seen questions on when to use IEnumerable over List but I understand the difference between the two. Describing vs implementing more or less. My question is more in regards to why the foreach over a local field, executes the IEnumerable and doesn't operate on the same objects referenced in the local variable.

Johnathon Sullinger
  • 7,097
  • 5
  • 37
  • 102
  • Possible duplicate of [IEnumerable vs List - What to Use? How do they work?](https://stackoverflow.com/questions/3628425/ienumerable-vs-list-what-to-use-how-do-they-work) – CodeNotFound May 08 '18 at 22:24

1 Answers1

2

Why isn't it referencing the same object that the Select creates?

Because foo is using Enumerable.Range which enumerates on-the-fly. There is no underlying data store that you are iterating over.

When you call foreach you are executing the underlying query, which creates 100 FooModel objects on the fly, which you modify.

When you call .All, you execute the query again, which creates another 100 Foo objects on the fly that have not been modified.

When you hydrate the results via ToList or ToArray, you are then looping over a concrete collection, and your changes to the underlying objects will persist.

D Stanley
  • 149,601
  • 11
  • 178
  • 240
  • I was wondering why Select had this side-effect but other LINQ methods like `Where` doesn't. It makes sense that this is the case, since a `Select` transform the object rather than just run a filter on the same series of objects. – Johnathon Sullinger May 08 '18 at 22:32