Why the call to Enumerable.First () appears to return a copy of the first element in an enumeration

Er, not quite sure how to express it, but ..

Given that IEnumerable was created using yield return containing three instances of the class, why does the .First () call seem to return a “copy” of the first instance?

See the following code;

public class Thing { public bool Updated { get; set; } public string Name { get; private set; } public Thing(string name) { Name = name; } public override string ToString() { return string.Format("{0} updated {1} {2}", Name, Updated, GetHashCode()); } } class Program { static void Main(string[] args) { Console.WriteLine("IEnumerable<Thing>"); var enumerableThings = GetThings(); var firstThing = enumerableThings.First(); firstThing.Updated = true; Console.WriteLine("Updated {0}", firstThing); foreach (var t in enumerableThings) Console.WriteLine(t); Console.WriteLine("IList<Thing>"); var thingList = GetThings().ToList(); var thing1 = thingList.First(); thing1.Updated = true; Console.WriteLine("Updated {0}", thing1); foreach (var t in thingList) Console.WriteLine(t); Console.ReadLine(); } private static IEnumerable<Thing> GetThings() { for (int i = 1; i <= 3; i++) { yield return new Thing(string.Format("thing {0}", i)); } } } } 

executed this produces the following output:

 IEnumerable<Thing> Updated thing 1 updated True 37121646 thing 1 updated False 45592480 thing 2 updated False 57352375 thing 3 updated False 2637164 IList<Thing> Updated thing 1 updated True 41014879 thing 1 updated True 41014879 thing 2 updated False 3888474 thing 3 updated False 25209742 

but I would expect that IList and IEnmerable would behave the same and output like this ...

 IEnumerable<Thing> Updated thing 1 updated True 45592480 thing 1 updated False 45592480 thing 2 updated False 57352375 thing 3 updated False 2637164 IList<Thing> Updated thing 1 updated True 41014879 thing 1 updated True 41014879 thing 2 updated False 3888474 thing 3 updated False 25209742 

What am I missing ?!

+4
source share
4 answers

The GetThings method returns not a real collection. It returns a “recipe” of how to “cook” a collection, and it is “cooked” only when you ask for iteration. This is the magic of yield .

That way, every time you call .First() , the loop works and, indeed, a new instance is created.

+3
source

An IEnumerable built with 'yield return' only produces values ​​when it is enumerated, and you enumerate it twice in the first case. In fact, you are creating a completely separate set of things when you list it a second time.

Return of income is basically a shortcut for the code that the state machine generates, which, when transferred, goes through the code to get the listed results. The results themselves are not saved anywhere until you do something with them, for example, put them on a list.

+1
source

Iterators (any method that uses yield return ) are evaluated with a lazy value when you iterate over them. This means that the body of your method is not executed when you call it, it is only executed when enumerating the resulting IEnumerable<T> by calling foreach or some such. And it is executed every time you foreach .

Since .First() should list IEnumerable<T> (since this is the only way to get elements from it), the body of your method is re-run every time you call .First() .

The usual solution is to force the iterator to start at some point when you are ready by calling .ToList() or .ToArray() . This will give you a List<T> or an array that will no longer change when it is restarted.

0
source

Your implementation of IEnumerable (GetThings) returns new elements every time it repeats. Thus, in foreach IEnumerable, every Thing is re-created. When you add a ToList to your IEnumerable, the list does contain a “copy” of each element that is derived from IEnumerable in the sense that the “things” created by your IEnumerable are stored in the list. Subsequent iterations over the list of "things" will always produce the same set of "things." Subsequent iterations over IEnumerable will always produce a new set of "things."

0
source

All Articles