Skip to content

Instantly share code, notes, and snippets.

@jcdickinson
Created July 8, 2015 18:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jcdickinson/f875229e671710cf1b34 to your computer and use it in GitHub Desktop.
Save jcdickinson/f875229e671710cf1b34 to your computer and use it in GitHub Desktop.
Return To SynchronizationContext
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
async void button1_Click(object sender, EventArgs e)
{
var context = SynchronizationContext.Current;
await Task.Delay(1000).ConfigureAwait(false);
// Now on non-UI thread.
await Task.Delay(1000).ConfigureAwait(context);
// Now back on UI thread.
throw new Exception("Oops!");
}
}
using System;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
public static class TaskExtensions
{
public struct ReturnToContextAwaitable
{
public struct ReturnToContextAwaiter : INotifyCompletion
{
private readonly SynchronizationContext _context;
private readonly TaskAwaiter _awaiter;
public bool IsCompleted { get { return _awaiter.IsCompleted; } }
public ReturnToContextAwaiter(TaskAwaiter awaiter, SynchronizationContext context)
{
_awaiter = awaiter;
_context = context;
}
public void GetResult()
{
_awaiter.GetResult();
}
public void OnCompleted(Action continuation)
{
var context = _context;
if (context == null) _awaiter.OnCompleted(continuation);
else _awaiter.OnCompleted(() => context.Send(RunAction, continuation));
}
private static void RunAction(object continuation)
{
((Action)continuation)();
}
}
private readonly SynchronizationContext _context;
private readonly Task _task;
public ReturnToContextAwaitable(Task task, SynchronizationContext context)
{
if (task == null) throw new ArgumentNullException("task");
_task = task;
_context = context;
}
public ReturnToContextAwaiter GetAwaiter()
{
return new ReturnToContextAwaiter(_task.GetAwaiter(), _context);
}
}
public struct ReturnToContextAwaitable<T>
{
public struct ReturnToContextAwaiter : INotifyCompletion
{
private readonly SynchronizationContext _context;
private readonly TaskAwaiter<T> _awaiter;
public bool IsCompleted { get { return _awaiter.IsCompleted; } }
public ReturnToContextAwaiter(TaskAwaiter<T> awaiter, SynchronizationContext context)
{
_awaiter = awaiter;
_context = context;
}
public T GetResult()
{
return _awaiter.GetResult();
}
public void OnCompleted(Action continuation)
{
var context = _context;
if (context == null) _awaiter.OnCompleted(continuation);
else _awaiter.OnCompleted(() => context.Send(RunAction, continuation));
}
private static void RunAction(object continuation)
{
((Action)continuation)();
}
}
private readonly SynchronizationContext _context;
private readonly Task<T> _task;
public ReturnToContextAwaitable(Task<T> task, SynchronizationContext context)
{
if (task == null) throw new ArgumentNullException("task");
_task = task;
_context = context;
}
public ReturnToContextAwaiter GetAwaiter()
{
return new ReturnToContextAwaiter(_task.GetAwaiter(), _context);
}
}
public static ReturnToContextAwaitable ConfigureAwait(this Task task, SynchronizationContext context)
{
if (task == null) throw new ArgumentNullException("task");
return new ReturnToContextAwaitable(task, context);
}
public static ReturnToContextAwaitable<T> ConfigureAwait<T>(this Task<T> task, SynchronizationContext context)
{
if (task == null) throw new ArgumentNullException("task");
return new ReturnToContextAwaitable<T>(task, context);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment