C# under the covers -- Enumerators
Following up on the comment stream to an earlier post, a few little bits revealed by the investigations, with a little help from ILSpy:
yield break;
is the equivalent of
return;
inside an iterator function -- by which I mean that any silent exit from the method is compiled to the equivalent of an explicit yield break;
, and
foreach(T x in y) { ... }
on exit from the iteration calls the Dispose()
method of the IEnumerator<T>
it uses implicitly to iterate over the collection y
; whereas, of course, explicit use of the enumerator MoveNext()
and Current
do not.
The behavioural constraints of IEnumerable
are weak enough as it is, being silent on whether replayability is part of the contract or not; this inconsistent disposal (with the IDisposable
interface being added only to the generic IEnumerator<T>
and not the .net 1.x vanilla version) makes guessing behaviours even worse when using LINQ methods like Skip
which does the dispose via using
when the iteration is exhausted
and Take
, which does it implicitly by the foreach
route before the iterator has been completely drained
There are probably similar wonders waiting to be unearthed in the F# collections APIs as well.
No comments :
Post a Comment