Given a SynchronizationContext, which I already have (and is basically a window to a specific thread), how do I create Tasks that are posted to this context?
For reference, here's a very basic demonstration of how the SynchronizationContext is set up.
public class SomeDispatcher : SynchronizationContext
{
SomeDispatcher() {
new Thread(() => {
SynchronizationContext.SetSynchronizationContext(this);
// Dispatching loop (among other things)
}).Start();
}
override void Post(SendOrPostCallback d, object state)
{
// Add (d, state) to a dispatch queue;
}
}
This works fine for async / awaits that are already running in the context.
Now, I want to be able to post Tasks to this from an outside context (e.g. from a UI thread) but can't seem to find a clean way of doing this.
One way to do this is by using TaskCompletionSource<>.
Task StartTask(Action action)
{
var tcs = new TaskCompletionSource<object>();
SaidDispatcher.Post(state => {
try
{
action.Invoke();
tcs.SetResult(null);
}
catch (Exception ex)
{
tcs.SetException(ex);
}
});
return tcs.Task;
});
But this is reinventing the wheel and a major pain supporting variations such as StartNew(Func<TResult>), StartNew(Func<Task<TResult>>), etc.
A TaskFactory interface to the SynchronizationContext is probably ideally, but I can't seem to instantiate one cleanly:
TaskFactory CreateTaskFactory()
{
var original = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(SomeDispatcher); // yuck!
try
{
return new TaskFactory(TaskScheduler.FromCurrentSynchronizationContext());
}
finally
{
SynchronizationContext.SetSynchronizationContext(original);
}
}
(i.e. Having to temporary hose the current thread's synchronization context seems hacky.)