2

This is probably pretty subjective, but how do people generally lay out their loop control in C# when the control variable is updated in the loop? The pedant in me doesn't like the separate declaration and repetition involved. eg.

string line = reader.ReadLine();
while (line != null)
{
    //do something with line

    line = reader.ReadLine();
}

The C coder in me wants to change this to

while (string line = reader.ReadLine() != null)
{
    //do something with line
}

but C#'s expressions don't seem to work that way :(

GazTheDestroyer
  • 20,722
  • 9
  • 70
  • 103

6 Answers6

7

Options:

1) Declare the variable the loop, but assign it in the condition:

string line;
while ((line = reader.ReadLine()) != null)
{
}

2) Use a for loop instead:

for (string line = reader.ReadLine(); line != null; line = reader.ReadLine())
{
}

3) Create an extension method to turn a reader into an IEnumerable<String> and then use:

foreach (string line in reader.ReadLines())
{
}

Personally I like the last one where possible - otherwise I'd use the first form.

C.Evenhuis
  • 25,996
  • 2
  • 58
  • 72
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • You could make that last one a `var`, no? I mean, if your colleagues cannot figure out that the result of `ReadLines` is a `string`, the solution is not explicit typing but immediate sacking :-) – Jörg W Mittag Nov 24 '11 at 14:10
  • 1
    @JörgWMittag: I could, but I'm not sure there's any benefit in doing so. – Jon Skeet Nov 24 '11 at 14:11
4

You can't declare a variable inside an expression.

You can write

string line;
while (line = reader.ReadLine() != null)

To make it clearer, I prefer to write

string line;
while (null != (line = reader.ReadLine()))

However, the best alternative is

foreach(string line in File.ReadLines(path) {

}

This will perform equivalently.
If you're reading some other stream, you can create an extension method that uses the previous syntax to enable foreach loops.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
2

Personally, I prefer:

string line;
while (line = reader.ReadLine() != null)
{
  ...
}

There's always the for construct as an alternative though:

for (string line = reader.ReadLine(); line != null; line = reader.ReadLine())
{
  ...
}
Rich O'Kelly
  • 41,274
  • 9
  • 83
  • 114
1

I usually write something like:

string line;
while((line = reader.ReadLine()) != null)
{
}
Stmated
  • 477
  • 5
  • 17
0

I agree that repeating the reader.ReadLine() expression isn't good. One way is to use while(true) and break:

while(true)
{
  string line = reader.ReadLine();
  if(line == null)
    break;

  //do something with line
}
Anders Abel
  • 67,989
  • 17
  • 150
  • 217
0

How about:

public static IEnumerable<R> ToSequence<T, R>(this T self, 
    Func<T, R> yielder, Func<R, bool> condition)
{
    R result = yielder(self, R);
    while (condition(result))
    {
        yield return result;
    }
}

and then use it something like this:

foreach (var line in reader.ToSequence(
    (r) => r.ReadLine(), 
    (line) => line != null))
{
    // do some stuff to line
}

or would you prefer:

foreach (var line in reader.NotNull(r => r.ReadLine()))
{
    // do some stuff to line...
}

that could be defined as:

public static IEnumerable<R> NotNull<T, R>(this T self, Func<T, R> yielder)
{
    return self.ToSequence(yielder, (r) => r != null);
}
Daren Thomas
  • 67,947
  • 40
  • 154
  • 200