13

Task or Task<TResult> object is awaitable, so we can use await key on those whose return value is Task or Task<TResult>. Task or Task<TResult> are the most frequently-used awaitable object.

We also can define our own awaitable object.The object should has below qualification.

  1. It has a GetAwaiter() method (instance method or extension method);
  2. 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.

My question is that why Microsoft didn't provide a interface to constrain these awaitable object? The current method to implement awaitable object is a little complicated.

roast_soul
  • 3,554
  • 7
  • 36
  • 73
  • 1
    You're asking why GetAwaiter is a convention rather than an ITask interface method? Microsoft answered this question somewhere... I wish I could recall where. – Cory Nelson Dec 28 '12 at 05:47

3 Answers3

13

It is best answered in Lucian Wischik's blog post Why must async methods return Task?

In summary (and I am not doing the blog post justice, you should read it), the issue is that Task already exists, so introducing an interface would mean

  • All the internal methods would need to be changed to the interface, a break change and thus almost impossible for the framework people to willingly do.
  • As a programmer you would constantly need to decide if you want to return Task or the interface, a decision that doesn't matter much.
  • The compiler would always need a concrete type, so even if you returned an interface from a method then it would still be compiled as Task.

The impact from the above is so massive that it doesn't make sense to provide an interface.

Robert MacLean
  • 38,975
  • 25
  • 98
  • 152
  • 3
    Actually, they made that change in Windows RT, where async operations return IAsyncOperation objects, to accomodate non-.NET languages. Now tasks are used to wrap the IAsyncOperation objects – Panagiotis Kanavos Dec 28 '12 at 08:53
  • @PanagiotisKanavos Task is equal to IAsyncOperation but async operations in C# still return Task. They use metadata on compile to bridge the differences. I am not 100% clear on it, but that is how I understand it, so in theory it means you are right & and you are wrong ;) – Robert MacLean Dec 31 '12 at 08:24
  • WinRT has no notion of tasks. In fact, even in C#, you can call `await` on an operation that *doesn't* return a taks as long it returns an object with a GetAwaiter method. Tasks in WinRT are kust a wrapper when you need to work on the return value itself – Panagiotis Kanavos Dec 31 '12 at 08:38
  • @PanagiotisKanavos Agreed, WinRT doesn't have a notion of Tasks - that is a .NET feature. The compiler converts the .NET stuff into WinRT items using projection. .NET can also await anything that implements GetAwaiter (see the link I posted) – Robert MacLean Dec 31 '12 at 10:42
5

This is in line with what they did for the foreach keyword (see section 8.8.4 of the C# language specification "The foreach statement").

Basically, it's duck-typing; if the type implements a MoveNext method and a Current property, that's all that's needed for the C# compiler to know how to iterate through a sequence exposed by an object.

This also applies with collection initializers (see section 7.6.10.3 of the C# language specification "Collection Initializers"); the only requirement is that the type implements the System.Collections.IEnumerable interface and have an Add method.

That said, the await keyword just sticks to prior precedent, not requiring specific interface implementations (although the interfaces supply those methods if you choose to use them), just a pattern of methods that the compiler can recognize.

casperOne
  • 73,706
  • 19
  • 184
  • 253
1

I think the main reason is what you stated in point #1

instance method or extension method

Simply, because they want to enable the user to make an object Awaitable by defining an extension method for it, hence, you can make an object Awaitable even if you don't own it.

Checkout this article

Ashi
  • 806
  • 1
  • 11
  • 22