using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var @this = new Program();
Console.WriteLine("Main before");
try
{
@this.Outer().Invoke();
}
catch (Exception e)
{
Console.WriteLine("Main caught exception!");
Console.WriteLine(e);
}
Console.WriteLine("Main after");
Console.ReadLine();
}
IEnumerable<IContinuation> Outer()
{
Console.WriteLine("Outer before");
/* what i want:
* yield Inner2();
*/
yield return Inner2().PrepareYield();
/* What i want to type: (give me a way to extend the c# language and this is possible :)
* try
* {
* int result = yield Inner();
* }
* catch
* {
Console.WriteLine("Caught exception!");
* }
*
* This does two things, receiving exceptions thrown from a child continuation, and return values.
*/
// What i needed to type:
int result;
Holder<int> r = new Holder<int>();
var y = Inner(r).PrepareYieldAndComplete();
yield return y;
try
{
y.Complete();
result = r.Value;
}
catch (Exception e)
{
Console.WriteLine("Outer caught exception!");
Console.WriteLine(e);
throw;
}
Console.WriteLine("Outer after");
}
IEnumerable<IContinuation> Inner(Holder<int> result)
{
Console.WriteLine("Inner before");
if (result != null)
throw new Exception();
//Console.WriteLine("Inner after");
yield break;
}
IEnumerable<IContinuation> Inner2()
{
Console.WriteLine("Inner2 before");
Console.WriteLine("Inner2 after");
yield break;
}
}
class Holder<T>
{
public T Value { get; set; }
}
interface IContinuation
{
IEnumerable<WaitHandle> Handles();
bool Process();
}
interface IPassThroughContinuation : IContinuation
{
void Complete();
}
static class ContinationExtensions
{
public static IPassThroughContinuation PrepareYieldAndComplete(this IEnumerable<IContinuation> self)
{
return new PassThroughContinuation(self);
}
public static IContinuation PrepareYield(this IEnumerable<IContinuation> self)
{
return new CombinedContinuation(self);
}
public static bool WaitAny(this IEnumerable<WaitHandle> self)
{
if (self == null)
return true;
foreach (var w in self)
if (w.WaitOne(0, false))
return true;
return false;
}
public static void Invoke(this IEnumerable<IContinuation> self)
{
var c = self.PrepareYield();
while (true)
{
c.Handles().WaitAny();
if (!c.Process())
break;
}
}
}
class PassThroughContinuation : IPassThroughContinuation
{
private IEnumerator<IContinuation> source;
private Exception exception;
private bool done;
private IContinuation value;
public PassThroughContinuation(IEnumerable<IContinuation> source)
{
this.source = source.GetEnumerator();
}
public IEnumerable<WaitHandle> Handles()
{
if (done||(value == null))
return null;
return value.Handles();
}
public bool Process()
{
if (done)
return false;
try
{
if (value != null)
if (value.Process())
return true;
if (!source.MoveNext())
{
done = true;
return false;
}
value = source.Current;
return true;
}
catch (ContinuationException ce)
{
exception = ce.InnerException;
done = true;
return false;
}
catch (Exception e)
{
exception = e;
done = true;
return false;
}
}
public void Complete()
{
if (!done)
throw new InvalidOperationException();
if (exception != null)
throw new ContinuationException(exception);
}
}
class CombinedContinuation : IContinuation
{
private IEnumerator<IContinuation> source;
private bool done;
private IContinuation value;
public CombinedContinuation(IEnumerable<IContinuation> source)
{
this.source = source.GetEnumerator();
}
public IEnumerable<WaitHandle> Handles()
{
if (done || (value == null))
return null;
return value.Handles();
}
public bool Process()
{
if (done)
return false;
try
{
if (value != null)
if (value.Process())
return true;
if (!source.MoveNext())
{
done = true;
return false;
}
value = source.Current;
return true;
}
catch
{
done = true;
throw;
}
}
}
class ContinuationException : Exception
{
public ContinuationException(Exception exception)
: base("Exception raised inside a continuation", exception)
{
}
}
}