コルーチンをC#で

前回のコルーチンっぽいものをC#で書いてみた。いろいろ問題があるかもしれないけど。
無限ループなので、Ctrl+Cかなんかで中断すべし。

/// <summary>The class which represent the co-routines which should be work cooperatively.</summary>
/// <typeparam name="T">The type of return value of co-routines.</typeparam>
class Coroutines<T>
{
	/// <summary>The co-routines which should be work cooperatively.</summary>
	List<Func<IEnumerable<T>>> _routines;

	/// <summary>Constructor with routines.</summary>
	public Coroutines(params Func<IEnumerable<T>>[] tasks)
	{
		_routines = new List<Func<IEnumerable<T>>>(tasks);
	}

	/// <summary>Invoke each coroutine</summary>
	/// <param name="proc">The procedure which uses return value of the co-routine.</param>
	public void DoWork(Action<T> proc)
	{
		// prepare the iterators
		int nRoutines = _routines.Count;
		List<IEnumerator<T>> enums = new List<IEnumerator<T>>();
		for (int i = 0; i < nRoutines; i++) enums.Add(_routines[i]().GetEnumerator());

		// invoke each co-routine
		// each one is supposed to be invoked lazily but I am not sure about that... :-(
		for (; ; )
		{
			for (int i = 0; i < nRoutines; i++)
			{
				enums[i].MoveNext();
				T val = enums[i].Current;
				proc(val);
			}
		}
	}
}

/// <summary>The test program of co-routine.</summary>
class Program
{
	static void Main(string[] args)
	{
		// register co-routines
		Coroutines<string> tasks = new Coroutines<string>(Enumerate3, Enumerate5);
		// invoke
		tasks.DoWork(Console.WriteLine);
	}

	/// <summary>co-routine No.1</summary>
	static IEnumerable<string> Enumerate3()
	{
		for (; ; )
		{
			yield return "one";
			yield return "two";
			yield return "three";
		}
	}

	/// <summary>co-routine No.2</summary>
	static IEnumerable<string> Enumerate5()
	{
		for (; ; )
		{
			yield return "いち";
			yield return "に";
			yield return "さん";
			yield return "し";
			yield return "ごー!";
		}
	}
}

単に手続きの中断と再開だけならIEnumerableを返すメソッドの中でyield return使えば実現できるけど、一方のコルーチンの計算結果を他のコルーチンに与えたい場合などはもっと工夫が必要っぽいなぁ。