To start, await Task.Yield().ConfigureAwait(false) will not work because Yield does not return Task . There are other ways to go to the pool stream, but using them is also not recommended, check "Why is SwitchTo removed from Async CTP / Release?"
If you still want to do this, here is a good trick using the fact that ConfigureAwait(false) pushes the continuation to the pool thread if there is synchronization in the original thread, although there is no asynchrony here:
static Task SwitchAsync() { if (SynchronizationContext.Current == null) return Task.FromResult(false); // optimize var tcs = new TaskCompletionSource<bool>(); Func<Task> yield = async () => await tcs.Task.ConfigureAwait(false); var task = yield(); tcs.SetResult(false); return task; } // ... public async Task DoSomethingAsync() { // We are on a thread that has a SynchronizationContext here. await SwitchAsync().ConfigureAwait(false); // We're on a thread pool thread without a SynchronizationContext await DoSomethingElseAsync(); // no need for ConfigureAwait(false) here // ... }
Again, this is not something that I widely use myself. I had similar problems about using ConfigureAwait(false) . One of the results was, while ConfigureAwait(false) might not be completely perfect, using it with await once you don't care about the synchronization context is the way to go. In this guide, the .NET source code itself follows.
Another result: if you are worried about third-party code inside DoSomethingElseAsync that might not use ConfigureAwait(false) correctly, just follow these steps:
public async Task DoSomethingAsync() {
This will use the Task.Run override, which accepts the Func<Task> lambda, runs it in the pool thread, and returns the expanded task. You would only do this for the first await inside DoSomethingAsync . The potential cost is the same as for SwitchAsync : one additional stream switch, but the code is more readable and more structured. This is the approach that I use in my work.
Noseratio
source share