I love the smell of

in the morning
Everything here is my opinion. I do not speak for your employer.
December 2007
January 2008

2007-12-21 »

Thread-free coroutines in C# 3.0

As I suspected, C# 3.0 has everything we need to accomplish a clone of WvCont from WvStreams in C++. It took a bit of fiddling to figure it out, but the final answer is simple and elegant.

The code below shows a ToAction() extension method that lets you convert any iterator into an Action, so that anywhere a "normal" callback is expected, you can provide a coroutine instead.

We do some non-obvious tricks with variable scoping in ToAction(), but that only has to be written once. The syntax for using it is simple.

using System;
using System.Collections;
using System.Linq;

public static class Example
{
    public static Action ToAction(this IEnumerable aie)
    {
    bool must_reset = false;
    IEnumerator ie = aie.GetEnumerator();
    return new Action(delegate() { 
        if (must_reset)
        ie = aie.GetEnumerator();
        must_reset = !ie.MoveNext();
    });
    }

    static IEnumerable demofunc(string prefix, int start, int end)
    {
    for (int i = start; i <= end; i++)
    {
        Console.WriteLine("{0}: {1}", prefix, i);
        yield return null;
    }
    // falling through here is like an extra yield
    }

    public static void Main()
    {
    Action a1 = demofunc(" *   ", 1, 3).ToAction();
    Action a2 = demofunc("   * ", 100, 200).ToAction();

    for (int i = 0; i < 10; i++)
    {
        a1();
        a2();
    }
    }
}

And the output looks like this:

 *   : 1
   * : 100
 *   : 2
   * : 101
 *   : 3
   * : 102
   * : 103
 *   : 1
   * : 104
 *   : 2
   * : 105
 *   : 3
   * : 106
   * : 107
 *   : 1
   * : 108
 *   : 2
   * : 109

The above program requires Mono 1.2.6 or higher (compile with "-langversion:linq") in Linux, or .NET 3.5 or higher in Windows.

I'm CEO at Tailscale, where we make network problems disappear.

Why would you follow me on twitter? Use RSS.

apenwarr on gmail.com