As most people who do any .NET related programming probably know, a short while ago, the next major version of the .NET framework and the tools that goes with it was released. This includes (but may not be limited to) Visual Studio 2012, .NET 4.5 and C# 4.5. One of the major new features of the .NET framework is its new support for async programming. Now, async programming has always (or rather, for as long as I can remember having wanted to do anything async) existed. For instance, if you create a Socket-instance, you have “BeginReceive” and “EndReceive” which provides asynchronous capability, however using them can be cumbersome. Normally you need a class to keep track of state, or you end up with a bunch of closures (given that you have .NET which is new enough to support closures). What this new capability does is to make it easy to create asynchronous code, and it generally does so with the help of Tasks.
My quest for answers with regards to the await-keywords starts with the new release of Reactive Extensions. Reactive Extensions mainly does it’s work with a single interface; “IObservable<T>”. Now, because this is an interface, there is no way (that I know of) it could implement Task<T>. Neither, does (as far as I know) Task<T> implement IObservable<T>, meaning there is no connection between them what so ever. Here you might probably wonder why I’m stressing this out, and the reason for that is rather simple. While writing code working with IObservable<T>, Visual Studio kept telling me how IObservable<T> was awaitable! In other words, I could write await in front of any instance of IObservable<T>!
How could this be? Certainly, as I just explained, there is no connection between IObservable<T> and Task<T>. The answer, has to do with awaiters.
Awaiters, as I found after some googling, turns out to be one of the most curious compiler-patterns I’ve ever seen. From what I understand, for a type (lets call the instance myWait for now) to be awaitable, the following must be true:
- myWait.GetAwaiter() must be a valid expression
- myWait.GetAwaiter().IsCompleted must be a bool-property that is gettable, and returns a value indicating weather or not myWait is completed.
- myWait.GetAwaiter().GetResult() must be a valid expression, and must be a method that returns the result of the async operation, in other words, the result of “(await myWait)”.
- myWait.GetAwaiter().OnCompleted(Action continuation) must be a valid method that takes a single Action and quest that method for execution when the async operation is finnished.
Notice that I’ve stated that myWait.GetAwaiter must be a valid expression? What I find curious about this, is that it must be a valid expression for the compiler, not a valid method of myWait. In other words, GetAwaiter can be an extension method! This makes it possible to do some rather absurd things with await like await a TimeSpan (to delay the current execution), given that you provide a one-line extension-method for TimeSpan. More about this can be found here:
Last in this article I’d like to say a few words about a small project of mine, named SpotiFire. SpotiFire is a wrapper around the libspotify API’s, that makes it fairly easy for a .NET application to interact with spotify. The last update to SpotiFire (uploaded today) enables the use of async for a lot of operations. Here is a simple sample showing how easy some of the operations that used to be hard to do is: