I suggest you ...

In the async CTP, I have to use the return type Task<T> (or Task) for any async method. Behind the scenes, this code is expanded do invoke an AsyncMethodBuilder and all kinds of things. The expansion basically allows for generic continuation-passing style. However, the concrete classes Task<T> etc. are really specialized for asynchronous programming using multi-threading.

If I could use my own type instead of Task<T>/Task, I could use async/await for anything. I could create methods that present a web page in the middle of their execution, and just continue at the next postback. (In fact, that's what I want to do.) But I could also implement all kinds of control flow manipulation.

Rationale:
- CPS is extremely powerful and can be really useful
- you would impress the lambda-the-ultimate crowd
- C# has a history of transforming code to a different text representation and then try and compile it (started with using/Dispose() and continued until LINQ)

Thanks for taking the time to share this suggestion. This item has been around for a couple of versions of Visual Studio and we haven’t acted on it. Looking at the VS “15” plans, we’re not going to take action on this item, so we’re going to close it. If the suggestion is still relevant, please either take a look to see if there’s another suggestion that’s similar that you can vote on, or open a new suggestion.

For background we did try to design async methods with arbitrary return types (as long as they supported a certain pattern), but there were several subtleties that caused us to give that up. One was that overload resolution needs to "see through" to the underlying result type of a "Task" and we couldn't think of a good way to generalize that.

To be clear, you can build pretty much any functionality on top of Task<T>. It is not strongly tied to threads, and it is quite efficient. So functionally you can build other types with async methods by wrapping their Task<T> results with your own type.

I believe this holds even for serialization. If you wrap the Task<T> returned from an async method in your own serializable type (say MyTask<T>) and never expose the Task<T> itself to the outside world, then your type can track the exact state of the Task<T> by registering a single continuation to that Task<T>. MyTask<T> can track continuations whichever way it wants, and run them whichever way it wants when it gets triggered from the completion of the underlying Task<T>.

Joshua, I have no issues with the GetAwaiter pattern or anything else the compiler does. It's only the hard-coded usage of the Task class that carries all the often unneccessary threading baggage. But to be honest, my only real issue is the serialization problem. Everything else I tried can be solved with Task/Task<T>, even if it does carry a lot of weight.

You really should learn the GetAwaiter() pattern and INotifyCompletion/ICriticalNotifyCompletion, then you would realize that asynchrony has nothing to do with threads and everything to do with linearizing event-driven coding. Threading is just the obvious best first application of it.

Just to add another argument:
Think how much cooler a node.cs with automatic CPS would be than node.js with all that manual inside-out CPS-style coding! And considering all the hype that node.js gets these days...
Unfortunately, Task<T> is all about threading, and node.js is all about how asynchronous programming is more efficient without threads...

I don't fully understand the async stuff as of yet, but my vague understanding thus far is that you could use your own types as awaitable (the 'MyTask' class in your code) just by having a GetAwaiter method available (as you mentioned, it's the same kind of 'just find and use this method' as foreach/GetEnumerator and others).

If I'm wrong and what you're asking for isn't doable with the existing compiler approach, is there any chance you could phrase it in terms of this Jon Skeet blog post to help others (or, at least, me :) understand how you're asking for something different than allowing your own class to be awaitable?

Task, AsyncMethodBuilder and friends cannot be serialized, simpler classes without all the built-in asynch execution features could more easily. I'm sure there are other cases too where the specific implementation of Task & Co. would get in the way, but haven't tested.