tags:

views:

794

answers:

5

There are two ways to read data from RichTextBox line by line

1 ) use a for loop to loop through lines of a richtextBox

String s=String.Empty;
for(int i=0;i<richtextbox.lines.length;i++)
 {
     s=richTextBox.Lines[i]
 }

2 ) use a foreach loop to enumerate richTextBox.Lines collection

   String s=String.Empty;
   foreach(string str in txtText.Lines)
    {
       s=str;
    }

There is a huge difference in performance when we use foreach loop to enumerate array collection for richtextbox.

I tried with 15000 lines.for loop took 8 minutes to just loop down to 15000 lines.while foreach took fraction of a second to enumerate it.

Why is this behaviour there?

+9  A: 

I think the Lines property is recalculated every time you want to access it. Consequently, the foreach method performs the calculation only once, while every time your reference Lines[i] it's re-evaluating the whole thing. Try caching the result of Lines property and checking again:

String s = String.Empty;
var lines = richtextbox.Lines;
for(int i = 0; i < lines.Length; i++)
{
    s = lines[i];
}

By the way, your question makes an implicit assumption that foreach is always slower than for. This is not always true.

Mehrdad Afshari
but then why is it so fast using foreach.
Rohit
foreach will translate to a single call to `Lines` property. It calls `GetEnumerator()` on it and only uses the resulting enumerator. The `Lines` property is never called again.
Mehrdad Afshari
+1 The Lines property, inherited from TextBoxBase, reads the Text property and loops through it, character by character, to split them into rows. Calling that 30k times (15k loops, twice to check length and read value) will be slower than calling it once.
Simon Svensson
WinForms is full of non-O(1) properties. These kind of things should really be methods IMO. Making them properties can cause headaches in hunting down performance bugs.
Mehrdad Afshari
IS there any way to choose between for and foreach loop.
Rohit
Rohit: `foreach` is usually preferred unless you need to access things by index. If what you are trying to do is "for every item in the collection, do this thing" in your mind, you should normally go with `foreach`.
Mehrdad Afshari
+3  A: 

Probably because finding the next line in the textbox takes time. When you use random-access by indexing in the first case, it must find that line from scratch. When the iteration is done internally by foreach, it can retain state and quickly find the next line.

This should make the first case run in O(n^2) time, while the second runs in O(n).

unwind
even after removing "s=richTextBox.Lines[i]",it took that much time.I wondered just iterating over is taking so long.
Rohit
See my answer for why it's still slow after removing that line.
Jon Skeet
A: 

Could it be that each line is being copied to a new string variable (str) on each loop? I'm guissing here, but you could probably verify the theory with this code

String s = String.Empty;
for (int i = 0; i < richTextBox.Lines.Length; i++)
{
    string str = richTextBox.Lines[i];
    s = str;
}
Jan Aagaard
No, that's got nothing to do with it I'm afraid. The assignment to the variable is virtually free.
Jon Skeet
A: 

.NET Reflector is very useful to determine why you're seeing performance you don't expect.

Give it a try to look at the Lines get accessor to see what it actually does each time you access it.

frou
+4  A: 

As Mehrdad noted, accessing the Lines property takes a long time. You need to be careful here - you're accessing it twice in each iteration at the moment:

String s = String.Empty;
for (int i = 0; i < richTextBox.Lines.Length; i++)
{
    s = richTextBox.Lines[i];
}

Even if you remove the access in the body of the loop like this:

String s = String.Empty;
for (int i = 0; i < richTextBox.Lines.Length; i++)
{
}

you're still accessing Lines on every iteration to see if you've finished!

If you don't want to foreach, you can just fetch Lines once:

string[] lines = richTextBox.Lines;
for (int i = 0; i < lines.Length; i++)
{
    s = lines[i];
}

Personally I prefer the foreach unless you really need the index though :)

Jon Skeet