| |||||||||
The C# yield-foreach howto
The C# yield-foreach howtoOne of the cool features of the C# language, is the ability to quickly create an enumerable projection of what a class is an abstraction for. Providing an enumerator for users of the class is often a very desirable solution
yield return and yield break to accomplish this.
Basically, for each value to return using the yield return construct. And when there are no more values to return,
use the yield break construct. At compile-time, the compiler will then generate a highly efficient state machine to
perform the underlying business logic of the enumerator.
It is important to realize, that although syntactically almost identical to the Python language, the C# version is far less general. It is not a generator in the
traditional sense, and hence is only applicable if the return type of the method is IEnumerable or IEnumerator!
Below is a class Program which exemplify a class that represents some collection of data.
Users of this class can use getSomeStuff() to acquire an enumeration that can be iterated using foreach or LINQ.
Central to this solution is the interface IEnumerable. More on this below.
using System;
using System.Collections.Generic;
namespace yield_foreach {
class Program {
static void Main (string[] args) {
var p = new Program();
foreach ( var s in p.getSomeStuff() ) {
Console.WriteLine(s);
}
}
public IEnumerable<int> getSomeStuff() {
for ( int i = 0; i < 5; i++ ) {
yield return i;
}
yield break;
}
}
}
The yield trapWhile the example is straight forward, there is one trap lurking in the dark. Especially if you are a less experienced developer. The core "problem" is that the methodgetSomeStuff() can either have the return type IEnumerable
or IEnumerator. If you use the IEnumerator type, however, the above program fails to compile with the message: foreach statement cannot operate on variables of type 'System.Collections.Generic.IEnumerator<int>' because 'System.Collections.Generic.IEnumerator<int>' does not contain a public definition for 'GetEnumerator' The problem, as stated in the compile-error, is that the IEnumerator type does not contain a method named
GetEnumerator(). If we insist on using the return type, we can accomplish this with a few modifications as highlighted in bold.
We simply change how we use the foreach and we rename the method to create the enumerator.
using System;
using System.Collections.Generic;
namespace yield_foreach {
class Program {
static void Main (string[] args) {
var p = new Program();
foreach ( var s in p ) {
Console.WriteLine(s);
}
}
public IEnumerator<int> GetEnumerator()
{
for ( int i = 0; i < 5; i++ ) {
yield return i;
}
yield break;
}
}
}
Have fun with this powerful language construct.
-Kasper
CommentsIf you have any comments to this article, please drop me a mail at firstclassthoughts at gmail dot com please indicate if I can't publish whole or parts of your comment on the site.If you like this site consider Help spread the wordShare this post on your favorite social bookmarking sites:
The most recent contributions 28/07/09 Magic in mathematics II Fun with the number cyclic numbers, and specifically with 142857 as it is the smallest of such numbers. 13/07/09 My top 8 time-saving Firefox shortcuts This article presents my favorite top 8 time-saving shortcuts in Firefox 3.0 and Firefox 3.5. Get to know these and you'll be saving a lot of time. They have been ordered by "the element of most surprise" 20/05/09 Board Game Jungle speed / Arriba Review of the cool game "Jungle Speed" aka. "Arriba". 16/05/09 Danish Twin words "Twin words" are words that not only have multiple meanings, they must be composed next to each other in meaningful sentences. This article explores the concept of twin words. Nothing of interest? Try browsing the entire article archive... | |||||||||