简体   繁体   中英

Why does IEnumerable.ToList produce new objects

public class TestClass
{
   public int Num { get; set; }
   public string Name { get; set; }
}

IEnumerable<TestClass> originalEnumerable
   = Enumerable.Range(1, 1).
                Select(x => new TestClass() { Num = x, Name = x.ToString() });

List<TestClass> listFromEnumerable = originalEnumerable.ToList();

// false
bool test = ReferenceEquals(listFromEnumerable[0], originalEnumerable.ElementAt(0)); 

If I modify the copied object the original does not change.

I understand from this that System.Linq.IEnumerable<T> collections will always produce new objects even though they are reference types when calling ToList() / ToArray() ? Am I missing something as other SO questions are insistent only references are copied.

Actually, the reason this is false is because your enumerable actually gets enumerated twice , once in the call originalEnumerable.ToList() , and a second time when you invoke originalEnumerable.ElementAt(0) .

Since it enumerates twice, it ends up creating new objects each time it is enumerated.

You're missing the fact, that Enumerable.Range is lazy, so this line actually produce nothing but in-memory query definition:

IEnumerable<TestClass> originalEnumerable
   = Enumerable.Range(1, 1).
                Select(x => new TestClass() { Num = x, Name = x.ToString() });

Calling ToList() fires the query and creates list with new items:

List<TestClass> listFromEnumerable = originalEnumerable.ToList();

Calling originalEnumerable.ElementAt(0) here

bool test = ReferenceEquals(listFromEnumerable[0], originalEnumerable.ElementAt(0)); 

fires the query again, and produces yet another new items.

Update

So you should say, that Enumerable.Range produces new items, not ToList() .

If your source collection would be already evaluated (eg TestClass[] array) ToList() won't create new items:

IEnumerable<TestClass> originalEnumerable
   = Enumerable.Range(1, 1).
                Select(x => new TestClass() { Num = x, Name = x.ToString() })
                .ToArray();

List<TestClass> listFromEnumerable = originalEnumerable.ToList();

// true
bool test = ReferenceEquals(listFromEnumerable[0], originalEnumerable[0]); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM