Is it possible for async method to ever return null in C#?

Viewed 2957

Digging through some old code, I have noticed a call to an asyncmethod and then a check for the task being returned for null.

async Task<Something> DoSomeStuffAsync()
{
    //...
    return null; //not the actual return, but I guess it doesn't matter
}


var result = DoSomeStuffAsync(); //without await
if(result == null)
{
    //does this part makes any sense
}

From my understanding of the async keyword, this scenario will never be possible because the result of an async method will always be wrapped in a Task but just to check, am I missing something?

Is there any case when an async method will return null in C#?

3 Answers

It's not possible for a method marked async to return null.

However, for the caller, a method is not async or not, it just returns an awaitable (a Task... or other awaitable types, that's out of the scope of the question), so it's indeed possible that it returns null.

I.e., the caller can't distinguish between:

async Task Foo()
//...

and:

Task Foo()
//...

And the latter method can perfectly return null

So a null check is perfectly valid for the caller

According to MSDN article async methods can have the following return types:

  • Task, for an async method that returns a value.

  • Task, for an async method that performs an operation but returns no value. void, for an event handler.

  • Starting with C# 7.0, any type that has an accessible GetAwaiter method. The object returned by the GetAwaiter method must implement the System.Runtime.CompilerServices.ICriticalNotifyCompletion interface.

  • Starting with C# 8.0, IAsyncEnumerable, for an async method that returns an async stream.

So Task represents the execution of the asynchronous method and it should never be null, because Task represents the ongoing process for the caller with a commitment to produce an actual value when the work is complete.

While it's true that DoSomeStuffAsync() could someday be changed into a method that is not async, it's pretty clear that it's intended to be async and you've probably found a bug. The call was probably meant to be awaited. If the call wasn't meant to be awaited (i.e., result was really meant to be a Task) then the null check is pointless, and there should probably be a comment explaining why the call wasn't awaited.

Testing for potential future API changes like it becoming possible for DoSomeStuffAsync() to return null is not something that belongs in production code. Not trusting API contracts and documentation ("Async" in the method name is a form of documentation) and littering code with pointless null checks is characteristic of inexperienced coders.

Related