I often come across the following pattern.
while(GetValue(i) != null)
{
DoSomethingWith(GetValue(i++));
}
Here GetValue
is executed twice. It would be much nicer to use a pattern where we can evaluate AND store the outcome of GetValue
. In some case (streams) it is impossible to get the value twice (see alternatives below for workarounds). Is there any pattern or loop construct we can use?
Some alternatives that I thought of with their own drawbacks.
Alternative 1
// Variable outside of loop scope, extra if
var value = null;
do
{
value = GetValue(i++);
if(value != null) { DoSomethingWith(value); }
} while(value != null);
Alternative 2
// Two get values, variable outside of loop
var value = GetValue(i);
while(value != null)
{
DoSometingWith(value);
value = GetValue(++i);
}
Alternative 3
// Out only works on reference types, most enumerables do not have
// a TryGet like method so we need to create our own wrapper
Object value;
while(TryGetValue(i++, out value))
{
DoSomethingWith(value);
}
Ideal world scenario (not valid C#)
while((var value = GetValue(i++)) != null)
{
DoSomethingWith(value);
}
Best Answer
Near "Ideal World" Solution
The following is valid C#
Compare with your "Ideal world scenario":
All I had to do was to pull
value
outside the loop. You seem willing to do this for all the presented alternatives. Thus, I don't think this is too much of a stretch."Infinite" While alternative
I have been playing around with the alternatives... here is another one:
In this case you can declare
value
inside the loop (and usingvar
), you don't need to check fornull
twice, you don't need to callGetValue
twice with the same input, and you don't have to create a wrapper with anout
parameter.Alternative using For
We may try to express the same thing using a
for
loop. Although, the naive approach does not work:The problem with this version is that it starts with
value
beingnull
, which meets the exit criterion, and thus you get no iterations.As JimmyJames points out you can write it like this:
The only drawback I see is that you need to write the type (you can't use
var
).Addendum: This is another variant suggested by Maliafo:
While this version requires to write
GetValue
, it doens't call it twice with the same value.Do you want to declare
i
in the scope too? Have a look at this:This is the same loop that we see in the "infinite" while solution I posted above. Yet, since I had no condition on the while... why not use change it to a
for
to incrementi
?Addendum: Also see NetMage's answer for an interesting use of C# 7.0 features.