StringBuilder All Over The Place
I don’t know how many people do this, but it’s all over the project I’m working on presently and I wanted to vent about it (and I wanted to post something here since I haven’t in ages).
StringBuilder is for assembling an unknown number of components into a string, most usefully for looping through some data and pulling something from it to put in the string.
When bigData.Count > N this increases performance a lot over string concatenation. However, when you’re assembling a string out of a fixed number of components, StringBuilder is like getting in the car and driving to get to the other side of a one-lane street with no traffic.
Most often this stems from one of three places:
- The developer doesn’t know C# well, and thinks things like this are necessary all the time, or that to get things on new lines easily they must do this, or to mix method results and literals, etc..
- The developer doesn’t realize how wasteful it is to introduce a new object and a bunch of method calls for nothing. I grant that this doesn’t matter in many cases, but I’ve seen hundreds of lines of SQL assembled this way for no particular reason in performance-critical code.
- The developer is doing conditional string building, and they don’t realize that there are nicer ways to do this that are either more readable or more efficient if not both.
There are multiple better ways to do this, so I’ll go over them here.
A very old fashioned solution, but effective. String literal concatenation can happen at compile-time in C#, so this is pretty efficient:
Not multiplatform safe, nor as readable as it could be due to the ‘\n’ character, so try this one:
Better - these are environment-sensitive and so will use the appropriate character(s) for a new line. The same-line strings have also been combined for readability since they don’t need to be their own lines. This is tied with the next entry for readability in my opinion.
This one uses a string function which does essentially the same as a few concatenations. If you trust that Microsoft (or Mono, etc.) has done everything the best way, this is a good bet. If you don’t, there’s the reference source to read. Tied with the previous for the most readable in my opinion, but you don’t have to have “Environment.NewLine” all over in this one, so as long as string.Join doesn’t cost performance this is preferable for code brevity.
This one takes it back to newline literals to avoid any extra concatenation, but uses a different string function which replaces numbered insertions like “{0}” here with the passed-in objects in string form.
This one concatenates just the last bit, in case we’re paranoid that string.Format is too performance intensive when just adding one value (hint: it is, there’s no reason to run a formatting algorithm to append a string to the end of a string!). This is probably the best choice for this particular scenario as far as efficiency goes.
Included for completeness is the verbatim string literal.. This isn’t an appropriate scenario for this, but if you have lots of pre-formatted text that you want in the code and not in a file for some reason, or any number of other scenarios, this is a good tool to know about. Only double quotes need to be escaped in this, which you can do by doubling them up.
Any of these approaches are acceptable, whether they’re ideal or not, but using StringBuilder for something like the bad example above just grinds my gears in a way I can’t quite express in few words, so I wrote lots of words as you can see.
Hopefully someone learns something from this, whether it’s when not to use StringBuilder or just a new way of doing things from one of my examples above.