A first port of call might be to extract the generated code with Reflector into a Visual Studio .NET C# source file. Sadly, an attempt at compilation will result in errors :( It turns out that the generated IL code does some things that ordinary C# programs are forbidden to do.
Specifically, the iterator syntax magic creates an implementation of IEnumerator
To see this programming style in action, one approach might be to write a simple program from scratch that demonstrates how you could mimic the behaviour of calling a method multiple times and returning to the same point you previously left off. C# is not going to be the right language choice since it forbids the very programming style we want to emulate! It turns out that a simple C++ program is a good candidate for demonstrating the concept and has the benefits of being compilable and therefore debuggable and also reasonably easy to understand.
As an example, consider the following C++ program that displays the first 6 prime numbers with a function GetPrime() that when called each time will return the next prime number in the array.

For simplicity, the program uses several global variables but it’s not hard to imagine these being hoisted into a class as member variables with the GetPrime() function elevated to method status.
The program begins life by calling GetPrime() for the first time. At this time, the global variable called ‘state’ has a value of zero, so the code enters the while loop and extracts the first prime number from the array and sets the global variable ‘state’ to 2 before returning the prime number from the function. The next call into GetPrime(), we note that ‘state’ has a value of 2, so it will trigger the case that causes the code to jump back into the middle of the while loop (effectively jumping back to the exact position where it left last time had it not returned from the function) with goto getAnotherPrime and so the code loops round to extract the next prime number from the array and returns it to the caller. When the global variable ‘count’ is no longer less that the number of primes in the array, the while loop in GetPrime() will drop out and cause the function to return zero, thus causing the while loop in _tmain() to terminate.
The naughty part of the code from a C# perspective is the goto label (getAnotherPrime) appearing after a return statement, something the C# compiler considers to be unreachable code (which seems quite reasonable).
So the secret of the technique is to maintain a state machine in memory of where the code is at in the loop. If ‘state’ is 2, then it means the next call to GetPrime() should re-enter the loop at the place it last left off (that place being just after the return statement). If 'state' is 0, then this is the very first call into the function and iteration is commencing. When 'state' has the value 1, it doesn't stay that way for long since the code will loop back round and soon become 2 again. The assignment of value 1 into 'state' doesn't have much effect other than keeping the compiler happy such that the label actually serves a purpose.
If you understand the above code then it should now be reasonably trivial for the reader to decompile the following C# program with Reflector and see how it uses this exact same state machine technique in IEnumerator