I happened to come across the following code the other day.
string cost = "FR" + "E" + "E"; // bad perf = true J
Which, after my performance investigation the other day, got me wondering again. Is there performance really going to be bad? Surely the compiler could figure this one out?
Turns out the C# compiler will optimize this, so unlike JIT compiler optimizations you can see the result by looking at the assembly’s IL. The variable cost is not readonly or const, so the compiler isn’t getting any additional hints about your plans here.
The quickest way to see what’s going on is to compile the code and view it using Reflector. Reflector reverse engineers to source code from the IL not the assembly code generated by the JIT compiler, so it can give you an idea what the C# compiler actually generated. Here’s what Reflector shows you:
string cost = "FREE"; Console.WriteLine(cost);
You can also look at the IL with ILDASM.EXE which shows you the same thing:
IL_0000: nop IL_0001: ldstr "FREE" IL_0006: stloc.0 IL_0007: ldloc.0 IL_0008: call void [mscorlib]System.Console::WriteLine(string)
Either way you can see that the compiler has removed the superfluous string addition.
Before you get lazy with all your string assignments, think again. The compiler can only be so smart. For example, take the following case:
string not = "NOT!!! "; string cost = not + "FR" + "E" + "E"; Console.WriteLine(cost);
Here the strings really are being concatenated at runtime, cost is not initialized to "NOT!!! FREE", it is built up from the two sub-strings.
IL_0000: nop IL_0001: ldstr "NOT!!! " IL_0006: stloc.0 IL_0007: ldloc.0 IL_0008: ldstr "FREE" IL_000d: call string [mscorlib]System.String::Concat(string, string) IL_0012: stloc.1 IL_0013: ldloc.1 IL_0014: call void [mscorlib]System.Console::WriteLine(string)
All this really tells you is that second guessing the compilers is a tricky thing. You need to figure out a lot of it on a case by case basis and most of the time clarity of the source code and time spent thinking about the algorithms is better than time spent pulling apart the results of compilation.
If you’re really interested in this stuff then you’re reading the wrong blog. Eric Gunnerson’s C# blog is a great place to look for interesting C# related tidbits. For some real performance insights check out Vance Morrison’s Weblog. Vance is an Architect on the .NET Runtime Team, specializing in performance issues with the runtime or managed code in general, so he really understands this stuff. He’s written some code timer classes to help you measure the performance of small pieces of code like this. I got them added into my code over the weekend. There’s also Rico Mariani’s blog, which is always full of good insights into the inner workings of the CLR.