jleslie48 said:
Excellent discussion Gentlemen, thank you for your inputs.
First off, both of you referred to xxxx.Length. I believe in both
cases you mean xxxx.Lines.Count()
the count of the number of lines of the multiline text box.
Did you try compiling the code examples? The Length property being used
is from the string[] array, not the textbox itself.
I will suggest that in Jeff's examples, it's not a great idea to
repeatedly retrieve the Lines property value. The array returned is
necessarily a copy of the actual data; at best, the array needs to be
created and initialized for each call to the getter, and it's entirely
possible all of the string instances are created as well.
Better would be to just get the property value once into a local
variable and then reuse that array instance as needed.
But as far as the Length vs Count() thing goes, inspecting the Length
property of the string[] array is in fact correct.
Pete you have concluded correctly that my 1000/300 split was exactly
an attempt to keep the program cpu from thrashing as the log file
grew. I will be taking a look at your custom control solution as
well.
Jeff, Sure you only replace output02.text once, but you still go
through the pain of a for loop to build up newText (also how does the
magic of memory allocation work here, my old school c training tells
me that the old target.text string[] structure has just become a
memory leak, and the newtext memory allocator in ??stringbuilder??
(more new stuff to me) is new allocation.) Actually this whole
memory allocation thing scares me in C# ala Microsoft. Too much
magic.
It's not magic. It's garbage collection. Memory resources cannot be
leaked at all in .NET, not in the conventional sense. Your own code can
mistakenly keep references to memory you never actually will use again,
but only if the memory is actually reachable by your code some way will
it remain allocated.
I'm not really sure what concern you have with Jeff's code anyway, with
respect to memory allocations. The only object that he explicitly
allocates (and thus does not explicitly free) is the StringBuilder
instance. The AppendLine() method may indeed need to reallocate the
internal buffer, but you could see exactly the same kind of API in a
C/C++ library (and in fact, you do when using STL types like vector).
The allocations and memory management are encapsulated within the class
and as such, they "just work".
It's true he doesn't explicitly free the StringBuilder instance itself.
But that's just how a GC-based system works.
As for Jeff's loop, as my own example shows, I agree that there is a
more efficient way to approach the problem. But Jeff's version is
definitely better than the one you posted, which has multiple problems:
• Setting the Text property repeatedly is inefficient
• Retrieving the Lines property repeatedly is inefficient
• Using the Lines property as a way of analyzing the line lengthis
inefficient
• Assuming that the text always uses "\r\n" as the line terminator is
incorrect
• Creating a new string instance each iteration of the loop is
inefficient
I was thinking the best solution was the old school C way. something
like this:
output02.Text =
output02.text.remove
( 0, //always the first character when looking at the Text as a
char[]
(&output02.Lines[301][0] - 1) - &output02.Lines[0][0])
);
that fancy line is address subtraction, I take the address of the
character just before the first character of the 301st line and
subtract from it the address of the first character period. This
should be the length of all the characters of the first 300 lines.
the question is, what has C# done to the syntax to accomplish this???
Your "old school" C way doesn't work anyway (not even counting the more
mundane bugs in the code). You can only perform the pointer arithmetic
that way if your array is a plain multi-dimensional array, where the
length of each row is a constant for the entire array. But the array
returned by the Lines property is an array of strings, each string
containing (essentially) an array of characters.
Even in C or C++, that's not compatible with the plain multi-dimensional
array assumption.
Now, that said, it's _possible_ there may be some efficiency gain by
taking advantage of the TextBox methods that manage line/character
positions and operate on the text directly. Specifically, here's an
alternative implementation of the Trim() method I posted earlier:
void Trim(TextBox text, int max, int remove)
{
int count = text.GetLineFromCharIndex(text.TextLength) + 1;
if (count > max)
{
int removeChars = text.GetFirstCharIndexFromLine(remove);
text.Select(0, removeChars);
text.SelectedText = "";
}
}
This implementation has the potential to be the _most_ efficient way to
accomplish it, at least while still using the built-in TextBox control.
That's because it allows all of the complicated logic to occur within
the control implementation itself, operating only in the internal data
structures without having to present the internal data to the client
code via managed objects like instances string or string[]. But, at the
same time, you are then delegating the efficiency quality to that
implementation, trusting that they are doing the right thing.
Sometimes that works out. Sometimes it doesn't.
![Smile :) :)](/styles/default/custom/smilies/smile.gif)
I can't tell you
whether for the TextBox class the above is actually going to be better.
But you can easily try it and find out yourself (noting, of course
that whatever the current performance characteristics today, with a new
release of the library it could change).
Pete