![]() ![]() our MoveNext() logic implements the same for loop conceptually, but one step per call to MoveNext() if there is more data, Current is assigned with the thing we would have passed to yield return.later (and it could be much later), when the caller iterates ( foreach) the data, GetEnumerator() is invoked, which calls into our GeneratedEnumerator to act as the cursor over the data.when we call SomeSource, we create our GeneratedEnumerable which stores the state ( x) that was passed to SomeSource, and exposes the required IEnumerable API.firstly, we need some object to represent IEnumerable, but we also need to understand that IEnumerable and IEnumerator (as returned from GetEnumerator()) are different APIs in the generated version there is a lot of overlap and they can share an instance, but to help discuss it, I've kept the two concepts separate.If ( i throw new NotSupportedException() our "advance" logic public bool MoveNext() So hopefully you can see in the above how the consumer can access an unbounded forwards-only sequence via this MoveNext() / Current approach but how does that get implemented? Iterator blocks (anything involving the yield keyword) are actually incredibly complex, so I'm going to take a lot of liberties here, but what is going on is similar to: As an aside, historically (prior to C# 5) the compiler used to scope item outside of the while loop, which might sound innocent, but it was the source of absolutely no end of confusion, code erros, and questions on Stack Overflow (think "captured variables"). But fundamentally, the compiler calls GetEnumerator() on the expression passed to foreach, then creates a while loop checking MoveNext() (which defines "is there more data?" and advances the mechanism in the success case), then accesses the Current property (which exposes the element we advanced to). We have to be a little loose in our phrasing here, because foreach isn't actually tied to IEnumerable - it is duck-typed against an API shape instead the using may or may not be there, for example. ![]() So: we know that we can write a foreach loop (over a sequence) of the form: More importantly, it is useful to allow us to compare and contrast later when we look at how async changes things. Many folks may already be familiar with all of this, but hey: it helps to set the scene. Iterators in the sync worldīefore we discuss async iterators, let's start by recapping iterators. As always, if you want to see the actual code, tools like are awesome (just change the "Results" view to "C#" and paste the code you're interested in onto the left). I'm going to give some illustrations of what happens under the hood, but note: these are illustrations, not the literal generated expansion - this is deliberately to help show what is conceptually happening, so if I ignore some sublte implementation detail: that's not accidental. Here I'm going to discuss the mechanisms and concepts relating to async iterators in C# - with the hope of both demystifying them a bit, and also showing how we can use some of the more advanced (but slightly hidden) features. ![]()
0 Comments
Leave a Reply. |
AuthorWrite something about yourself. No need to be fancy, just an overview. ArchivesCategories |