Created
July 8, 2015 18:13
-
-
Save jcdickinson/f875229e671710cf1b34 to your computer and use it in GitHub Desktop.
Return To SynchronizationContext
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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!"); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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