Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Elvis (?.) operator doesn't work with async-await?

Let's have a code like this (fragment of App.xaml.xs):

public class MethodClass
{
    public async Task Job()
    {
        Debug.WriteLine("Doing some sob");
        await Task.Delay(1);
    }
}

public MethodClass MyClass = null;

protected async override void OnLaunched(LaunchActivatedEventArgs e)
{
    await MyClass?.Job(); // here goes NullreferenceException
    MyClass?.Job(); // works fine - does nothing

Why Elvis operator doesn't work with async-await? Am I missing something?

like image 729
Romasz Avatar asked Nov 05 '16 08:11

Romasz


People also ask

Does async await run synchronously?

Top-level code, up to and including the first await expression (if there is one), is run synchronously. In this way, an async function without an await expression will run synchronously. If there is an await expression inside the function body, however, the async function will always complete asynchronouslyasynchronouslyAsynchronous programming is a technique that enables your program to start a potentially long-running task and still be able to be responsive to other events while that task runs, rather than having to wait until that task has finished. Once that task has finished, your program is presented with the result.https://developer.mozilla.org › Asynchronous › IntroducingIntroducing asynchronous JavaScript - Learn web development | MDN.

Does await halt execution?

The possible suspension points in your code marked with await indicate that the current piece of code might pause execution while waiting for the asynchronous function or method to return.

Does await block thread?

The await operator doesn't block the thread that evaluates the async method. When the await operator suspends the enclosing async method, the control returns to the caller of the method.

Does MAP support async await?

The map doesn't resolve the promisespromisesIn other cases a future and a promise are created together and associated with each other: the future is the value, the promise is the function that sets the value – essentially the return value (future) of an asynchronous function (promise).https://en.wikipedia.org › wiki › Futures_and_promisesFutures and promises - Wikipedia on its own but left the stuff for the developer to resolve. So, that means you can't use async-await in the map.


1 Answers

The way await is translated is that first, GetAwaiter() is called on the awaited object (in your case, a Task). It then does some other complicated things, but those are not relevant here:

await MyClass?.Job();

Compiles to:

var awaiter = MyClass?.Job().GetAwaiter();
// more code

Since Task.GetAwaiter() is an instance method and you're calling it with a null Task, you get a NullReferenceException.


As a curiosity, it is possible to await a null awaitable, as long as its GetAwaiter() is an extension method that accepts null:

public class NullAwaitable { }

public static class Extensions
{
    public static TaskAwaiter GetAwaiter(this NullAwaitable _)
        => Task.CompletedTask.GetAwaiter();
}

public class MethodClass
{
    public NullAwaitable Job() => new NullAwaitable();
}

MethodClass MyClass = null;

await MyClass?.Job(); // works fine
like image 177
svick Avatar answered Oct 08 '22 19:10

svick