How to create and use a custom Awaitable in c#?
.net, async-await, c#
Solution
Fully implementing the awaitable pattern for production use is a tricky business - you need to capture the execution context, amongst other things. Stephen Toub's blog post on this has a lot more detail. In many cases, it's easier to piggy-back onto `Task<T>` or `Task`, potentially using `TaskCompletionSource`. For example, in your case, you could write the equivalent of `Task.Delay` like this:
public Task MyDelay(int milliseconds)
{
// There's only a generic TaskCompletionSource, but we don't really
// care about the result. Just use int as a reasonably cheap version.
var tcs = new TaskCompletionSource<int>();
Timer timer = new Timer(_ => tcs.SetResult(0), null, milliseconds,
Timeout.Infinite);
// Capture the timer variable so that the timer can't be garbage collected
// unless the task is (in which case it doesn't matter).
tcs.Task.ContinueWith(task => timer = null);
return tcs.Task;
}
You can now `await` that task, just like you can await the result of `Task.Delay`.
Problem
I'm trying to implement a custom awaiteable to execute `await Thread.SleepAsync()` without creating any additional threads. Here's what I've got: ``` class AwaitableThread : INotifyCompletion { public AwaitableThread(long milliseconds) { var timer = new Timer(obj => { IsCompleted = true; }, null, milliseconds, Timeout.Infinite); } private bool isCompleted = false; public bool IsCompleted { get { return isCompleted; } set { isCompleted = value; } } public void GetResult() {} public AwaitableThread GetAwaiter() { return this; } public void OnCompleted(Action continuation) { if (continuation != null) { continuation(); } } } ``` And here's how the sleep would work: ``` static async Task Sleep(int milliseconds) { await new AwaitableThread(milliseconds); } ``` The problem is that this function returns immidiatly, even though in `OnCompleted`, `IsCompleted` is still false. What am I doing wrong?