Je me souviens
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 AI runs on us, not the other way around.

Why would you follow me on twitter? Use RSS.

apenwarr on gmail.com