I've figured out a way to switch threads in the middle of a method. The benefit of that seems super obvious to me: that's what everyone wants to do anyway, and splitting up methods, using callbacks, or lambdas, or whatever is just code bureaucracy to make it work.
But if this is so obvious to me, Microsoft guys probably thought of that too, yet didn't implement it as the default way of doing things in TPL. This makes me nervous. These custom awaiters seem to run correctly, but maybe I just haven't hit the gotchas yet.
What could possibly go wrong?
public static class UsageTest
{
public static async Task DoItTheUsualWay()
{
// update UI
Dictionary<string, string> cantUseVar = null; // have to initialize
await Task.Run(() =>
{
// do heavy lifting
var cantAccessVarOutsideTheLambda = new object();
cantUseVar = new Dictionary<string, string>();
});
// update UI
}
public static async Task UseTheCoolNewAwaiters()
{
// update UI
await GoToThreadPool.Instance;
// do heavy lifting
var smoothSailing = new object();
await GoToMainThread.Instance;
// update UI
smoothSailing.ToString();
}
}
public class GoToThreadPool : INotifyCompletion
{
public static readonly GoToThreadPool Instance = new GoToThreadPool();
public bool IsCompleted
{
get { return Thread.CurrentThread.IsThreadPoolThread; }
}
public GoToThreadPool GetAwaiter()
{
return this;
}
public void GetResult() { }
public void OnCompleted(Action continuation)
{
ThreadPool.QueueUserWorkItem(o => continuation());
}
}
public class GoToMainThread : INotifyCompletion
{
public static readonly GoToMainThread Instance = new GoToMainThread();
public bool IsCompleted
{
get { return Thread.CurrentThread == Application.Current.Dispatcher.Thread; }
}
public GoToMainThread GetAwaiter()
{
return this;
}
public void GetResult() { }
public void OnCompleted(Action continuation)
{
Application.Current.Dispatcher.BeginInvoke(continuation);
}
}