13.07.2015 Views

C# in Depth

C# in Depth

C# in Depth

SHOW MORE
SHOW LESS
  • No tags were found...

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

166 CHAPTER 6 Implement<strong>in</strong>g iterators the easy wayFour l<strong>in</strong>es of implementation, two of which are just braces. Just to make it clear, thatreplaces the whole of the IterationSampleIterator class. Completely. At least <strong>in</strong> thesource code… Later on we’ll see what the compiler has done beh<strong>in</strong>d our back, andsome of the quirks of the implementation it’s provided, but for the moment let’s lookat the source code we’ve used.The method looks like a perfectly normal one until you see the use of yieldreturn. That’s what tells the <strong>C#</strong> compiler that this isn’t a normal method but oneimplemented with an iterator block. The method is declared to return an IEnumerator,and you can only use iterator blocks to implement methods 1 that have a return type ofIEnumerable, IEnumerator, or one of the generic equivalents. The yield type of the iteratorblock is object if the declared return type of the method is a nongeneric <strong>in</strong>terface,or the type argument of the generic <strong>in</strong>terface otherwise. For <strong>in</strong>stance, a methoddeclared to return IEnumerable would have a yield type of str<strong>in</strong>g.No normal return statements are allowed with<strong>in</strong> iterator blocks—only yieldreturn. All yield return statements <strong>in</strong> the block have to try to return a value compatiblewith the yield type of the block. To use our previous example, you couldn’t writeyield return 1; <strong>in</strong> a method declared to return IEnumerable.NOTERestrictions on yield return—There are a few further restrictions on yieldstatements. You can’t use yield return <strong>in</strong>side a try block if it has anycatch blocks, and you can’t use either yield return or yield break(which we’ll come to shortly) <strong>in</strong> a f<strong>in</strong>ally block. That doesn’t mean youcan’t use try/catch or try/f<strong>in</strong>ally blocks <strong>in</strong>side iterators—it justrestricts what you can do <strong>in</strong> them.The big idea that you need to get your head around when it comes toiterator blocks is that although you’ve written a method that looks like itexecutes sequentially, what you’ve actually asked the compiler to do iscreate a state mach<strong>in</strong>e for you. This is necessary for exactly the same reasonwe had to put so much effort <strong>in</strong>to implement<strong>in</strong>g the iterator <strong>in</strong><strong>C#</strong>1—the caller only wants to see one element at a time, so we need tokeep track of what we were do<strong>in</strong>g when we last returned a value.In iterator blocks, the compiler creates a state mach<strong>in</strong>e (<strong>in</strong> the form of anested type), which remembers exactly where we were with<strong>in</strong> the block and what valuesthe local variables (<strong>in</strong>clud<strong>in</strong>g parameters) had at that po<strong>in</strong>t. The compiler analyzesthe iterator block and creates a class that is similar to the longhandimplementation we wrote earlier, keep<strong>in</strong>g all the necessary state as <strong>in</strong>stance variables.Let’s th<strong>in</strong>k about what this state mach<strong>in</strong>e has to do <strong>in</strong> order to implement the iterator:Compilerdoes allthe work!■■It has to have some <strong>in</strong>itial state.Whenever MoveNext is called, it has to execute code from the GetEnumeratormethod until we’re ready to provide the next value (<strong>in</strong> other words, until we hita yield return statement).1Or properties, as we’ll see later on. You can’t use an iterator block <strong>in</strong> an anonymous method, though.Licensed to Rhona Hadida

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!