简体   繁体   中英

Conversion from async lambda Action into Func<Task>?

We know the async equivalent of Action is Func<Task> .

Therefore we could write:

Func<Task> func = async () =>
        {
            Console.WriteLine(@"waiting ...");
            await Task.Delay(300).ConfigureAwait(false);
            Console.WriteLine(@"... finished");
        };

But it is also possible to write it as an Action :

Action action = async () =>
        {
            Console.WriteLine(@"waiting ...");
            await Task.Delay(300).ConfigureAwait(false);
            Console.WriteLine(@"... finished");
        };

This is syntactically correct. How is it possible to convert Action action into Func<Task> func ?

I think that the second snippet is similar to async void - just anonymous. You really should not use them except for some edge cases like WinForms event handlers..

The compiler manages the returned Task for you and puts it into default thread pool and runs continuations on some selected SynchroContext that is "known to be OK".. I don't remember the rest.. check the gory details of async-void and you will hit articles on why you shouldn't use it except for when absolutely necessary. for example:

Note for example differences in exception handling..

Aah, and I forgot to answer: If that's really async void then you cannot convert. Simply - the returned Task is gone and you can't obtain it. The Action you've got is something like:

Action action = () => 
{
    Func<Task> yourRealTask = async () =>
    {
        Console.WriteLine(@"waiting ...");
        await Task.Delay(300).ConfigureAwait(false);
        Console.WriteLine(@"... finished");
    };

    // ** some compiler-generated code to register/run the task somewhere
    // ** so it will be handled properly instea of being lost due to not
    // ** returning the Task to the caller

    return;
}

so, effectively, the yourRealTask is not obtainable.. with some luck you may hack it out of some closure via reflection, but.. don't do that. Just use Func<Task> .

The first case will create a normal Task factory.

The second will create a fire-and-forget async-void method, which is indeed used more rarely.

Since compiler is so neat, it can create both from a single anonymous method, and it's up to the programmer to decide which one he needs.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM