3

I've been reading lately articles and documentation about deferred execution, LINQ, querying in general etc. and the phrase "object is enumerated" came up quite often. Can someone explain what happens when an object gets enumerated?

Example article.

This method is implemented by using deferred execution. The immediate return value is an object that stores all the information that is required to perform the action. The query represented by this method is not executed until the object is enumerated either by calling its GetEnumerator method directly or by using foreach in Visual C#

marijuslau
  • 148
  • 1
  • 10
  • It tells you that in the next words: *calling its `GetEnumerator` method directly or by using `foreach`*. – GSerg Oct 15 '21 at 08:01
  • It also tells you that will be `iterable` after it `enumerated`. – Batuhan Oct 15 '21 at 08:05
  • Let's say the object is a list of generic items `List`. It already implements `IEnumerable` interface. Why does it need to be _enumerated_ for our query? What exactly changes in this List when we _enumerate_ it ? – marijuslau Oct 15 '21 at 08:11
  • What query are you referring to? The "why does it need to be enumerated" part is a little confusing: if you didn't enumerate, how would you ever access the values provided by the enumerable/enumerator? – ProgrammingLlama Oct 15 '21 at 08:15
  • Any query we execute on the data source – marijuslau Oct 15 '21 at 08:16
  • 2
    Nothing changes in the list while you enumerate it. Enumeration is a way of accessing the list. Indexing into the list would be another way. Some collections don't even have indexers and can only be thought of as *sequences of items*, which is what IEnumerable represents. Enumeration means "I am now going to access this collection as a *sequence of items* because it suits my current goal". – GSerg Oct 15 '21 at 08:19
  • 2
    [FYI](https://sharplab.io/#v2:CYLg1APgAgTAjAWAFBQAwAIpwCwG5nJQDMmM6AwugN7Lp2YlTboCyAFAJTW328AyASwDOAFwA8AgHYiAfOgCG6ALzpJAUwDu6QaInSZnfEl68AZgHsATmvkBjABbo2AN3mX0rgDbopCjjxNuY0D0AF8AsORQoA==) this is what `foreach` on a `List` does once it's compiled. – ProgrammingLlama Oct 15 '21 at 08:21
  • Thanks for the last comment, GSerg. That really makes some things clearer now. – marijuslau Oct 15 '21 at 08:27

2 Answers2

6

General explainations for enumeration

IEnumerable is an interface, that is usually implemented by collection types in C#. For example List, Queue or Array.

IEnumerable provides a method GetEnumerator which returns an object of type IEnumerator.

The IEnumerator basically represents a "forward moving pointer" to elements in a collection. IEnumerator has:

  • the property Current, which returns the object it currently points to (e.g. first object in your collection).
  • a method MoveNext, which moves the pointer to the next element. After calling it, Current will hold a reference to the next object in your collection. MoveNext will return false if there were no more elements in the collection.

Whenever a foreach loop is executed on an IEnumerable, the IEnumerator is retreived via GetEnumerator and MoveNext is called for each iteration - until it eventually returns false. The variable you define in your loop header, is filled with the IEnumerator's Current.


Compiling a foreach loop

thx to @Llama

This code...

List<int> a = new List<int>();
foreach (var val in a)
{
    var b = 1 + val;
}

is transformed to something like this by the compiler:

List<int> list = new List<int>();
List<int>.Enumerator enumerator = list.GetEnumerator();
try
{
    while (enumerator.MoveNext())
    {
        int current = enumerator.Current;
        int num = 1 + current;
    }
} finally {
    ((IDisposable)enumerator).Dispose();
}

The quote

The query represented by this method is not executed until the object is enumerated either by calling its GetEnumerator method directly or by using foreach in Visual C#.

GetEnumerator is automatically called, as soon as you put your object into a foreach loop, for example. Of course, other functions, e.g. Linq queries, can also retreive the IEnumerator from your collection, by doing so either explicit (call GetEnumerator) or implicit in some sort of loop, like I did in my sample above.

Dominik
  • 1,623
  • 11
  • 27
  • I think my question was quite clear - why we need to enumerate our data source object and what does exactly happen during this enumeration. And you answered it perfectly, thanks. I don't understand the comments though, that the answer is self evident in my example article or that I don't understand deferred execution, the question is only about enumeration itself. Again, thanks. – marijuslau Oct 15 '21 at 08:20
1

I think you just need a good understanding of deferred vs. immediate execution for LINQ queries.

Deferred execution: When you write a LINQ query it is only executed when you actually access the results - deferred until you run code to iterate with i.e. a foreach over the results. This is the default behaviour.

Immediate execution: We can force this (which you'll see often in C# code) by appending a ToList() or similar method to the query.

Ben Hall
  • 1,353
  • 10
  • 19
  • Here's an overview: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/classification-of-standard-query-operators-by-manner-of-execution#classification-table – marsze Oct 15 '21 at 08:18