Iterator blocks have an interesting property: they defer execution. When the method (or property) is called, none of your code is executed – it only starts running when
MoveNext() is first called.
Deferred execution is a great thing in many ways, but it’s a pain when it comes to parameter checking. If you check parameters within an iterator block, you’ve effectively left a timebomb – the error will be potentially reported a long way from the original source of the problem. (Side-note: this is why I prefer using a cast to
as when I know what type something really should be – I’d rather get an
InvalidCastException immediately than a
NullReferenceException later on.)
One solution to this is to check the parameters in the public method and then call a private method which is implemented with an iterator block. That’s a bit ugly though. It would be nice to be able to specify the parameter checking in an initial block which could only occur at the start of the method – something like this simple implementation of
if (count < 0)
throw new ArgumentException(count);
for (int i=0; i < count; i++)
yield return element;
yield do for two reasons: it fits in with the rest of the
yield pattern, and by using an existing keyword I suspect it reduces/eliminates the chance of this being a breaking change. It’s not ideal from the point of self-description, but
do is the closest keyword I could find when I looked at the spec. In a language with
begin as a keyword, that would probably be a better choice – or
fixed appeals in that the code is fixed in the method rather than being shunted off into the compiler-generated type, but the normal use of
fixed is far too different to make this an appealing choice. Any other suggestions are very welcome
Is this an important enough change to make it worth including in C# 4? I’m not sure. The negative side is that I suspect relatively few people use iterator blocks much, so it may not have a very wide benefit. The positive side is that it only actually makes any difference to those who do use iterator blocks, and I believe almost all of them would find it a welcome addition. It’s simple to understand, and it makes iterator blocks much easier to use in a “correct” manner when any form of initial checking is involved.
Note, mostly to myself and Marc Gravell: I haven’t checked, but I suspect most of Push LINQ is broken in this respect.
Further note to self – I really need to fix my code formatter to treat
yield as a contextual keyword.