I have a setup as follows:
class mytype
{
Awaiter GetAwaiter() { ... }
}
class Awaiter : INotifyCompletion
{
bool IsCompleted { get { return false; } }
void GetResult () { }
void OnCompleted(Action continuation)
{
//that's the continuation in focus
}
}
//somewhere else:
async Task MyMethod()
{
//here instructions for 1st state
await new mytype();
//here instructions for 2nd state
await new mytype();
//here instructions for 3rd state
}
Am I mistaken, or is the delegate I get from the CLR (within the same method) always more or less the same delegate yet the instance I’m awaiting is different? The C# compiler translates the MyMethod because of the async keyword to a FSM with 3 states. And everytime I await something in that method in C#, internally the MoveNext-Method of the FSM is called. But the FSM keeps track of the states itself, so it knows the last state it was in, so it can proceed to the next state (and execute the instructions associated with the new state).
So essentially I understand that an Invoke of the delegate named continuation internally comes down to the call of the MoveNext-method of the appropriate FSM-Type. Seems like no big magic – or am I mistaken?
Yeah, your understand is right. The “big magic” happens when the compiler has to rewrite
MyMethod()into the state machine, not during runtime.For some more information about how the state machine looks like and how it works, read Jon Skeet’s article Generated code from a simple async method from his Eduasync series. That article describes the code generated by one of the Async CTPs, followup articles address changes since then: Changes between the Async CTP and the Visual Studio 11 Preview and Changes between the VS11 Preview and the Visual Studio 11 Beta.