Tales from the Evil Empire

Bertrand Le Roy's blog

News


Bertrand Le Roy

BoudinFatal's Gamercard

Tales from the Evil Empire - Blogged

Blogs I read

My other stuff

Archives

Yield and generics rock!

In this post, I'll try to show you why you should not limit your use of generics to strongly typed lists, and why yield may become your favorite new keyword.
Here's an example of how you can use both in a very simple piece of code.
Imagine you want to filter out an enumeration using an arbitrary function. For obvious performance reasons, you don't want to create a temporary list and filter that. You have to construct the filtered enumeration on-the-fly as the original enumeration is enumerated.
Of course, you can do that with .NET 1.1, but if you try it, you'll see that the code will be considerably more verbose. Here's how it may be done with .NET 2.0:
 

public sealed class FilteredEnumerable<T> : IEnumerable<T>, IEnumerable {

  private IEnumerable<T> _enumerable;
  private Predicate<T> _filter;

  public FilteredEnumerable(IEnumerable<T> enumerable, Predicate<T> filter) : base() {
    _enumerable = enumerable;
    _filter = filter;
  }

  IEnumerator<T> IEnumerable<T>.GetEnumerator() {
    foreach (T item in _enumerable) {
      if (_filter == null || _filter(item)) {
        yield return item;
      }
    }
  }

  IEnumerator IEnumerable.GetEnumerator() {
    return (IEnumerator)(((IEnumerable<T>)this).GetEnumerator());
  }
}

The class is constructed from two generics of types IEnumerable<T> and Predicate<T>. A Predicate<T> is a boolean function that takes an argument of type T. That will be our filtering function. The actual code, the generic GetEnumerator function, enumerates the original enumeration, tests if the predicate returned true for this item, and yields it only in this case.
You can use this class this way:
 

string[] stringsToFilter = new string[] {"Red", "Green", "Blue", "Pink"};
Predicate<string> filter = delegate(string stringToFilter) {
  return (stringToFilter.IndexOf('e') != -1);
};
filteredStrings = new FilteredEnumerable<string>(stringsToFilter, filter);

The filteredStrings enumerable then contains all strings from stringsToFilter that contain the letter "e": red, green and blue, but not pink. Pretty slick, eh? Note the use of an anonymous function here to construct the filtering predicate. Now, you've got a generic class that filters anything by any function.

Comments

Mike Griggs said:

C# starts to look more and more like C++/STL with every passing day...
# August 31, 2004 5:29 PM

Wesner Moise said:

For more concisely is to use the following iterator method

IEnumerable<T> FilteredEnumerable<T>(IEnumerable<T> en, Predicate<T> pred)
{
foreach(T t in en)
if ( pred(t) )
yield return t;
}

# August 31, 2004 5:36 PM