If I assume that for each value produced in the loop A that I should start a new loop B that in turn starts a new loop C AND I want the executions to run interleaved, then this does that:
public interface ICoroutine
{
void Run<T>(IEnumerable<T> source, Action<ICoroutine, T> action);
}
public static class CoroutineEx
{
private class Coroutine : ICoroutine
{
public List<IEnumerator> _enumerators = new List<IEnumerator>();
public void Run<T>(IEnumerable<T> source, Action<ICoroutine, T> action)
{
_enumerators.Insert(0, source.Do(t => action(this, t)).GetEnumerator());
}
}
public static void Run<T>(this IEnumerable<T> source, Action<ICoroutine, T> action)
{
var e = new Coroutine();
e.Run(source, action);
while (e._enumerators.Any())
{
foreach (var x in e._enumerators.ToArray())
{
if (!x.MoveNext())
{
e._enumerators.Remove(x);
}
}
}
}
public static void Run<T>(this IEnumerable<T> source, ICoroutine coroutine, Action<T> action)
{
coroutine.Run(source, (c, t) => action(t));
}
}
Now I can write this kind of code:
Enumerable
.Range(1, 3)
.Run((coroutine, loop_a) =>
{
Console.WriteLine($"a={loop_a}");
Enumerable.Range(1, loop_a).Run(coroutine, loop_b =>
{
Console.WriteLine($"a={loop_a}, b={loop_b}");
Enumerable.Range(1, loop_b).Run(coroutine, loop_c =>
{
Console.WriteLine($"a={loop_a}, b={loop_b}, c={loop_c}");
});
});
});
Here's the output of that run:
a=1
a=1, b=1
a=2
a=2, b=1
a=1, b=1, c=1
a=3
a=3, b=1
a=2, b=1, c=1
a=2, b=2
a=2, b=2, c=1
a=3, b=1, c=1
a=3, b=2
a=3, b=2, c=1
a=2, b=2, c=2
a=3, b=3
a=3, b=3, c=1
a=3, b=2, c=2
a=3, b=3, c=2
a=3, b=3, c=3