4

What are other restrictions on using async with a method signature and on using await with an expression in these methods, if there are any? So far, I am aware that a method marked with async can have only one of the following return types (maybe there are more?).

  • void
  • Task
  • Task<TResult>
4

3 回答 3

7

I have an intro on my blog that you may find helpful.

await only requires that it be passed an instance that is "awaitable" (matching a certain pattern, similar to how foreach works). The most common awaitables are tasks, but there are others (e.g., Windows Store asynchronous operations).

async must be used on any method that uses await. async methods must return Task or Task<T>, or, if you absolutely must, void.

于 2013-11-05T20:42:40.677 回答
6

The async modifier is only allowed on methods with a return type of void, Task, or Task<T>. In general, it should only be used on methods which include an await operator.

The await operator can be used on any type t where (From C# language spec, 7.7.7):

t has an accessible instance or extension method called GetAwaiter with no parameters and no type parameters, and a return type A for which all of the following hold:

  • A implements the interface System.Runtime.CompilerServices.INotifyCompletion
  • A has an accessible, readable instance property IsCompleted of type bool
  • A has an accessible instance method GetResult with no parameters and no type parameters

In practice, this typically means you can use await on any Task, Task<T>, IAsyncOperation, IAsyncOperation<T> (from Windows Store API), and a few other select types in the framework.

于 2013-11-05T20:49:04.737 回答
3

You have hit upon the major technical constraints of async methods. I would offer this additional guidance:

  1. It is pointless to declare an async method which does not await at least one operation, as such a method is equivalent to a regular, synchronous method.
  2. You should avoid writing async void methods. These are intended only to support the writing of asynchronous event handlers.
  3. If you call an async method, you should await it (or at least access the Task's IsFaulted status and retrieve its Exception if one occurred). If you do not, and one of the awaited operations inside that method throws an exception that you do not catch, that exception will be rethrown on the finalizer thread1 (bad).

You can await any object with an awaitable type, i.e., a type which declares a member:

TAwaiter GetAwaiter();

Where TAwaiter is a type declaring the following members:

bool IsCompleted { get; }
TResult GetResult();
void OnCompleted(Action continuation);  // inherited from INotifyCompletion

The IsCompleted property is self-describing: it returns true if the awaitable operation has already completed; otherwise, it returns false.

The GetResult() method returns the result of the operation, or returns void if the operation has no return type. It should throw if called while IsCompleted is false.

The OnCompleted() method is used to register a continuation, i.e., the code which is called upon completion of the operation. This member should actually be inherited from INotifyCompletion in the System.Runtime.CompilerServices namespace (all awaiters should implement this interface).


1This is no longer the default behavior in .NET 4.5, though it can still be enabled on the client machine through a configuration change.

于 2013-11-05T20:49:06.840 回答