+N Consulting, Inc.

Upon Reflection - C# yields statement enumeration helper

The new yields statement sounds very convenient. In the past, one had to write a significant amount of code to implement the IEnumerator interface and expose an enumerator. That included considerations of concurrency, a loop variable bound to the instance or other methods to maintain current loop value during enumeration.

Fret no more, a new syntax is in town - the yields statement.

With the yields statement, IEnumerator implementation folds down to a scan one liner:

public class MyCollection : IEnumerable
{
public IEnumerator GetEnumerator()
{
foreach (string s in new string[] { "Larry", "Moe", "Curley" })
{
yield return s + " is a stooge";
}
}
}

You can also provide an enumerator returning static values or “hard coded” number of values:

public class VerySimple : IEnumerable
{
public List<DateTime> _Things;
public IEnumerator GetEnumerator()
{
yield return 1;
yield return 7;
yield return 11;
}
}

So that sounds great! No pesky Reset(), MoveNext() etc., no private index to hold on to, and even options to do more fancy things, like exposing only some of your items to enumeration:

public class Person
{
public string Name;
public bool IsPublic;
public Person(string name, bool isPublic)
{
this.Name = name;
this.IsPublic = isPublic;
}
}
public class People : IEnumerable
{
private Person[] _Peeps = new Person[] {
new Person("James Brown", true),
new Person("John Lenon", true),
new Person("Johnny Doe", false)
};
public IEnumerator GetEnumerator()
{
foreach (Person dude in _Peeps)
{
if (dude.IsPublic)
{
yield return dude.Name + " is a well known";
}
}
}
}

That was easy, and pretty useful too. You get to have an easy syntax for emitting each value, and you get exact control over which item is exposed without implementing a whole sub class just for the enumeration.

Looking at this keyword and the simplicity of exposing enumerator one might be tempted to think there is some magic new framework for enumerating a collection with hooks and generic loops or something. To find out, I looked at the IL generated for the MyCollection class we just created.

As expected, we find the class has a method named GetEnumerator(). It’s implementation is seemingly simple, instantiate some cryptically named class and return it.

public IEnumerator GetEnumerator()
{
< GetEnumerator > d__0 d__ = new < GetEnumerator > d__0(0);
d__.<> 4__this = this;
return d__;
}

When you look at the implementation of the enumerator class itself, you get quite a few lines of code:

private sealed class <GetEnumerator>d__0 : IEnumerator<object>, IEnumerator, IDisposable
{
// Fields
private int <>1__state;
private object <>2__current;
public MyCollection<>4__this;
public string[] <>7__wrap2;
public int <>7__wrap3;
public string <s>5__1;
// Methods
public <GetEnumerator>d__0(int <>1__state)
{
this.<> 1__state = <> 1__state;
}
private bool MoveNext()
{
try
{
switch (this.<> 1__state)
{
case 0:
this.<> 1__state = -1;
this.<> 1__state = 1;
this.<> 7__wrap2 = new string[] { "Larry", "Moe", "Curley" };
this.<> 7__wrap3 = 0;
while (this.<> 7__wrap3 < this.<> 7__wrap2.Length)
{
this.< s > 5__1 = this.<> 7__wrap2[this.<> 7__wrap3];
this.<> 2__current = this.< s > 5__1 + " is a stooge";
this.<> 1__state = 2;
return true;
Label_0098:
this.<> 1__state = 1;
this.<> 7__wrap3++;
}
this.<> 1__state = -1;
break;
case 2:
goto Label_0098;
}
return false;
}
fault
{
this.Dispose();
}
}
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
void IDisposable.Dispose()
{
switch (this.<> 1__state)
{
case 1:
case 2:
this.<> 1__state = -1;
break;
}
}
// Properties
object IEnumerator<object>.Current
{
get
{
return this.<> 2__current;
}
}
object IEnumerator.Current
{
get
{
return this.<> 2__current;
}
}
}

So what is really going on here is that when you type out yield return x; the compiler transforms this into a method stub, implants your loop logic in the MoveNext() method of a new shiny enumerator class, and provides the standard requisite functions of IEnumerable interface which support the foreach statement.

Is this good or bad? Certainly it serves well in many instances. For most of your daily uses for an enumerator this should work quite well. It’s strongly typed to the list item and uses your class’s values referenced directly.

What can be sub optimal about this? Multithreaded applications need to implement locking at the class level. Some collections in .NET implement an internal version number such that if the collection chances during enumeration an exception gets thrown to the enumerating thread. Not so here. If you want that behavior you’d have to implement it yourself.

You should note that the loop itself and any of your conditions get transformed by the compiler. The transformation, I trust, is functionally equivalent. The transformation result will vary slightly based on the collection being iterated, or if you are using a static chain of yield statements. In the case of hard coded yielded values, no concurrency issues should arise, but that is fairly rare in my humble experience.

Besides that, I think it’s pretty cool. You get to write less code, the compiler take care of your code generation.

On a side note, when decompiling your code, don’t get too caught up in Reflector’s code rendering. For one, IL decompiled to your language of choice is not a symmetric operation. For that reason and due to compiler optimizations and inlining, certain language constructs may come up reflected as GOTO label but were not necessarily coded this way originally in the higher level language.

Notice

We use cookies to personalise content, to allow you to contact us, to provide social media features and to analyse our site usage. Information about your use of our site may be combined by our analytics partners with other information that you’ve provided to them or that they’ve collected from your use of their services. You consent to our cookies if you continue to use our website.