Enumerables in .NET
IEnumerable and IEnumerator
Collections in .NET implement
IEnumerable. This interface has just one method:
GetEnumerator(). It returns an implementation of
IEnumerator allows to
- move between elements in the collection
- read the current element
- reset state
Why do we even need
IEnumerable and don’t just implement
every collection type? That’s because we want to be able to enumerate a single
collection by multiple actors.
IEnumerator has a state. We can’t use the same
instance of it from two different services, because none of these services would
get a full picture of the collection. Instead, each service should retrieve its
own copy of
IEnumerable) and use it.
An example of an
IEnumerable is an
we can see that it implements
IEnumerable.GetEnumerator(). The enumerator
itself can be found
It keeps reference to the
Array. One of its components is the
property. All it does is it returns the element at the current
is also there. It basically increments the
This is a simple enumartor that just returns consecutive numbers, forever (well, until it overflows):
Here’s how we’d use it:
It would just print numbers forever.
foreach keyword is basically a syntax sugar that relies on the
Behind the scenes:
yield keyword is a shortcut that allows us to create our own
IEnumerators. For example, to create an infinite enumerator, we
don’t have to create new implementations of
we have to do is this:
It’s a method that uses the
yield keyword. It works in a way that each time we
ask for the next value from the returned
IEnumerable, it is going to execute
the loop iteration, until it finds the next
yield. In our case, there’s just 1
line of code in the loop, but there could be more.
yield creates a custom
IEnumerator (behind the scenes) that
returns values only when we ask for them. The code in the method using
runs ONLY when we ask for the next element. It is very similar to how LINQ
A small remark about LINQ and its
IEnumerable is that it is not always the
case that one element is pulled from the source at a time. In some cases we have
to know all the values upfront before we’re able to return even the first value.
Example of it are:
We can’t reverse a collection if we don’t know the last value.
IQueryable interface is a bit similar to
IEnumerable, but also totally
different at the same time. In fact, it inherits from
IQueryable is mostly used with LINQ and data providers. The advantage of it is
that is allows to construct a query before executing it against a data source
(e.g., a database).
IQueryable has a property called
Expression. This is the
expression tree that a given instance of
IQueryable represents. For example
(using Entity Framework):
This is turned into an expression tree, stored in the
Let’s say I add another line of code to what I had:
If we were using
IEnumerable, we’d request all the people from the database
first, and then (locally) extract three entities from that. It’s obviously
inefficient. However, thanks to the use of
IQueryable, when the
added, the expression tree got modified and the constructed SQL query could make
use of something like
TOP to deliver just 3 people instances.
Here’s a quote from MSDN:
The second property (Expression) gives you the expression that corresponds to the query. This is quintessential essence of IQueryable’s being. The actual ‘query’ underneath the hood of an IQueryable is an expression that represents the query as a tree of LINQ query operators/method calls. This is the part of the IQueryable that your provider must comprehend in order to do anything useful. If you look deeper you will see that the whole IQueryable infrastructure (including the System.Linq.Queryable version of LINQ standard query operators) is just a mechanism to auto-construct expression tree nodes for you. When you use the Queryable.Where method to apply a filter to an IQueryable, it simply builds you a new IQueryable adding a method-call expression node on top of the tree representing the call you just made to Queryable.Where.
IAsyncEnumerable and IAsyncEnumerator
An async version of
IEnumerator is the pair of
Here’s a comparison of their methods/properties:
Really, the most important difference between traditional and async Enumerable
is that the latter supports async loading of next items via
Here’s an example of how to use the
The compiler actually translates the
await foreach... into code that invokes
await e.MoveNextAsync() in a loop.
Async methods normally support cancellation.
GetAsyncEnumerator is no different. It accepts a
since we’re rarely calling that method directly (we use
await foreach instead,
which deals with enumerators behind the scenes), there’s a special way to pass
WithCancellation(ct) extension method passes the token.
On the other side, we also need to be able to accept
CancellationToken to our methods that return
IAsyncEnumerable. We use a special attribute for that:
The compiler will know that it should pass the
CancellationToken (that we
could provide via
WithCancellatin(...)) to our method.
LINQ does not support
IAsyncEnumerables by default. There’s a NuGet package
for that -
System.Linq.Async. Adding it
in is all we need to do, the namespace to import is just
System.Linq, like in
the standard LINQ.