In some scenarios it simplifies the code greatly.
It may or may not be applicable to your app.
Just a few weeks ago I was able to convert a nightmare-ish recursive asynchronous method to a `foreach` loop with `await`s inside.
It's cool when you can do this:
var providerExceptions = new List<Exception> ();
// Try each provider in turn
foreach (var pi in providers) {
token.ThrowIfCancellationRequested ();
try {
return await GetSession (provider, isLast, options, token);
} catch (TaskCanceledException) {
throw;
} catch (Exception ex) {
providerExceptions.Add (ex);
// Fall back to next provider
}
}
// Neither provider worked
throw new AggregateException ("Could not obtain session via either provider", providerExceptions);
Or this: async Task<Session> GetSession (AccountProvider provider, bool isLast, LoginOptions options, CancellationToken token)
{
if (!SessionManager.NetworkMonitor.IsNetworkAvailable)
throw new OfflineException ();
var account = await GetAccount (provider, !isLast, options);
if (account == null)
throw new Exception ("The user chose to skip this provider.");
var service = provider.Service;
var session = new Session (service, account);
if (service.SupportsVerification) {
// For services that support verification, do it now
try {
await service.VerifyAsync (account, token);
} catch (TaskCanceledException) {
throw;
} catch (Exception ex) {
throw new InvalidOperationException ("Account verification failed.", ex);
}
}
return session;
}
Depending on the conditions, the method may or may not “freeze”, but the calling code doesn't care.