I got some hard time figuring out how to "store" and call async lambdas in C#, it was basically trying by running. I find out some approach that work while others do not (below), I read about it but it it still unclear why some work and others not, can someone explain why and maybe add a better approach as well?
public static class Program
{
static async Task Main(string[] args)
{
// works fine, everything is printed
Console.WriteLine("Before 1 delay");
await Task.Delay(1000);
Console.WriteLine("After 1 delay");
// works fine, everything is printed
var foo = new Func<Task>(async () =>
{
Console.WriteLine("Before 2 delay");
await Task.Delay(1000);
Console.WriteLine("After 2 delay");
});
await foo.Invoke();
// works fine, everything is printed
var foo2 = new Action(() =>
{
Console.WriteLine("Before 3 delay");
Task.Delay(1000).Wait();
Console.WriteLine("After 3 delay");
});
foo2.Invoke();
// Does not work, just before is printed
var foo3 = new Action(async () =>
{
Console.WriteLine("Before 4 delay");
await Task.Delay(1000);
Console.WriteLine("After 4 delay");
});
foo3.Invoke();
}
}
Please notice that question is not the same as the following below, even when the answer is the same the context is different, as this question problem is basically why an Action delegate does run async even with the await being there, besides of that there is the "bonus" of "Why .Await() works, while await do not in a action delegate"
async Task vs async void “await” doesn't wait for the completion of call Why is the console window closing immediately once displayed my output? How to stop C# console applications from closing automatically?
The problem in your last approach is that you're wrapping an async lambda with an Action
, which describes a void
-returning function.
When await Task.Delay(1000);
executes, it tells the runtime to schedule the continuation (i.e. the instructions after that line) after the delay completes asynchronously.
The caller of the delegate at that point has no way of awaiting the inner-async function and its delay, so here we're in the context of an async void
invocation, where the operation will eventually complete but no Task-like
instance is returned. Since the caller is unable to wait for the function to terminate, it continues its execution until the Main
method exits.
In general, async void
should only be used for asynchronous event handlers, because as you saw doesn't allow the caller to properly await the function to complete.
Right way to create and call lambda of async methods in C#
// return a Task!
var wrapper = new Func<Task>(async () =>
{
await SomethingAsync();
});
await wrapper.Invoke();