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?

Rohit Raghuvansi
  • 2,824
  • 8
  • 46
  • 74

5 Answers5

13

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 :)

Mehrdad Afshari
  • 414,610
  • 91
  • 852
  • 789
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • if it's the accessing twice that is the issue then shouldn't it just take twice as long. But his difference is 8 min vs a fraction of a second. – barlop Sep 18 '16 at 22:52
  • 1
    @barlop: No, it's not the difference between once or twice, it's the difference between once and once-per-line. – Jon Skeet Sep 19 '16 at 05:28
10

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
  • 414,610
  • 91
  • 852
  • 789
  • but then why is it so fast using foreach. – Rohit Raghuvansi Jul 16 '09 at 11:01
  • 3
    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 Jul 16 '09 at 11:04
  • 4
    +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. – sisve Jul 16 '09 at 11:08
  • 1
    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 Jul 16 '09 at 11:13
  • IS there any way to choose between for and foreach loop. – Rohit Raghuvansi Jul 16 '09 at 11:21
  • 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 Jul 16 '09 at 11:23
3

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
  • 391,730
  • 64
  • 469
  • 606
0

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
  • 10,940
  • 8
  • 45
  • 80
0

.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.

xyz
  • 27,223
  • 29
  • 105
  • 125