简体   繁体   中英

If it's possible to write our own awaitables, then why can async methods only return Task<T>, Task and void?

I'm looking at the MSDN documentation and it says

Async methods have three possible return types: Task<TResult> , Task , and void .

https://msdn.microsoft.com/en-us/library/mt674893.aspx

However, I remember reading somewhere else that it's possible to write to await custom awaiters. How can I reconcile these 2 facts?

await supports any kind of "awaitable", which are object instances that follow a certain pattern ( GetAwaiter , etc).

async generates a state machine which only knows how to create Task / Task<T> awaitables (or return void ).

So, you can create your own custom awaitable object and return that, but you have to do it explicitly. You can't use async to do it.

The compiler team is currently looking at adding ValueTask support to async . This would allow you to use "async method builders" that would follow a pattern. Then you'd be able to use async as well as await to operate on any kind of "tasklike" type. Unfortunately, it would still not allow async methods to return interface types, though - changes in other parts of the language are necessary for that.

The native classes shipped with .NET (specifically TaskAwaiter) only support Task , Task<T> and void as awaitable, thus this is all MSDN tells you about. However, you can write custom awaiters that allow awaiting other types.

According to https://weblogs.asp.net/dixin/understanding-c-sharp-async-await-2-awaitable-awaiter-pattern , an object is awaitable if:

  • It has a GetAwaiter() method (instance method or extension method);
  • Its GetAwaiter() method returns an awaiter. An object is an awaiter if:
    • It implements INotifyCompletion or ICriticalNotifyCompletion interface;
    • It has an IsCompleted, which has a getter and returns a Boolean;
    • it has a GetResult() method, which returns void, or a result.

The first line of the link you provided reads as follows:

Updated: July 20, 2015

So this is a bit dated. With that said, originally async methods did only have Task<TResult> , Task , and void as valid returns types. According to the C# Language Specification the following is stated:

10.15 Async Functions

The return-type of an async method must be either void or a task type.

With the introduction of UWP , you get four more built-in types:

  1. IAsyncAction
  2. IAsyncActionWithProgress<TProgress>
  3. IAsyncOperation<TResult>
  4. IAsyncOperationWithProgress<TResult, TProgress>

These are considered "async types" and you are allowed to use the async and await keywords on them as you'd expect.

More from the spec:

The return-type of an async method must be either void or a task type . The task types are System.Threading.Tasks.Task and types constructed from System.Threading.Tasks.Task<T> . For the sake of brevity, in this chapter these types are referenced as Task and Task<T> , respectively. An async method returning a task type is said to be task-returning.

The exact definition of the task types is implementation defined, but from the language's point of view a task type is in one of the states incomplete, succeeded or faulted. A faulted task records a pertinent exception. A succeeded Task<T> records a result of type T . Task types are awaitable, and can therefore be the operands of await expressions

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