const int interval = 1000;
/* The results of the following are:
Begin
Using 'Await':Bar
Using 'Await':Foo
Using 'Result':Bar
Using 'Result':Foo
Using 'Wait':Bar
But 'Wait' doesn't have a 'Result' to dump out...
Nearly...
Missing 'Await'....:Foo
End
Missing 'Await'....:Bar
*/
void Main()
{
Console.WriteLine("Begin");
UseAwait().Wait();
UseResult().Wait();
UseResult().Wait();
UseWait().Wait();
"----".Dump();
InvokeUseResult().Wait();
//Block thread:
Task.Delay(interval).Wait();
Console.WriteLine("Nearly...");
//Block thread an older way:
Thread.Sleep(interval);
//This may continue on a background channel
//after Main is completed (may...):
MissingInternalAwait();
// But this line will certainly print before
// the above background thread completes
Console.WriteLine("End");
}
//-----------------------------------
// Convention is to suffix async methods with 'Async':
async Task UseAwait()
{
// Wait for results by using 'await'
// without blocking this thread:
var r = await FooAsync("Using 'Await'");
r.Dump();
}
async Task InvokeUseResult(){
// Even if you yourself use await, something further
// down could be blocking a thread using Result or Wait
// which sort of defeats the purpose (it freezes UX)
// a way to change that is use ConfigureAwait to
// break off to a new context:
await UseResult("forcing new context...").ConfigureAwait(false);
}
async Task UseResult(string prefix=null)
{
// The difference between using 'await' and 'result'
// is that Result blocks the thread.
// so should be avoided because it gives the
// feeling that you're doing async calls...but
// not really... It may give the illusion of being
// async in a console, but in a UI thread, where there is only
// one UI thread that you have to "sync" back to, can
// freeze interaction. Hence the use of ConfigureAwait(false)
// above
var r = FooAsync(prefix + "Using 'Result'").Result;
r.Dump();
}
async Task UseWait(){
//Same for 'wait' (a thread blocking outcome),
//but it's used for Tasks that have no result:
FooAsync("Using 'Wait'").Wait();
"But 'Wait' doesn't have a 'Result' to dump out...".Dump();
}
//-----------------------------------
//Intentional error:
async Task MissingInternalAwait()
{
// Wait for results by using 'await'
// without blocking this thread:
var r = FooAsync("Missing 'Await'....");
r.Dump();
}
//-----------------------------------
async Task<string> FooAsync(string prefix)
{
await Task.Factory.StartNew(() => Thread.Sleep(interval));
//Use Await within a task marked as async
await BarAsync(prefix).Dump();
return prefix + ":" + "Foo";
}
async Task<string> BarAsync(string prefix)
{
await Task.Delay(interval);
return prefix + ":" + "Bar";
}