Johnathon Sullinger
Johnathon Sullinger

Reputation: 7414

Changing Enumerated items aren't changed in original IEnumerable

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.

Upvotes: 1

Views: 56

Answers (1)

D Stanley
D Stanley

Reputation: 152644

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.

Upvotes: 2

Related Questions