Wednesday, January 14, 2009

StringBuilder and the immutability of strings

I had a discussion today with Robin, who claimed that there was several ways to break the immutability of strings in C# – most notably by using a StringBuilder to build the string in bits. I found that very unsettling, and decided to make my own tests to see what was happening. Here is a screenshot of the program and the results.

CropperCapture[4]

The results are pretty interesting, and not as unsettling as i had feared. It seems that immutability of the string is indeed broken for the string gotten from the StringBuilder as it is not the same reference to the string. This is at least what I thought was one of the porperties of string immutability in C#. Luckily both an Equals call and == report the strings as being the same.

What practical implications does this have? Obviously – do not rely on ReferenceEquals when testing string. But when would you do that. The only case I can think of right now is when testing:

CropperCapture[6]

Using “Assert.Same” (in xUnit – Assert.AreSame in NUnit), will fail. This is not something that I would normally do – I mostly use Equals and only Same when I really mean it. If you have a different strategy, maybe it is time to revisit it.

But what is really happening here?! You have to dig a litte bit to find out what is going on. In .NET strings are usually stored in the intern pool. This is the way to ensure immutability. This is true for all cases of literal strings at least. Even strings literals concatted with + have ths ability. But in some cases, apparently when strings are generated from char arrays, like when they come from interop or StringBuilder, strings will be put in the heap instead of the intern table. To the rescue comes the String.Intern() method which will correct all wrongs:

CropperCapture[7]

There. Now you know some more about the inner workings of strings. Lesson to be learned: Never ever use ReferenceEquals to compare strings. And if you are forced to – Intern them first.