From Richter and this discussion, I would expect any two “identical” strings to be the same reference. But just now in LINQPad I got mixed results on this topic. Here is the code:
void Main()
{
string alpha = String.Format("Hello{0}", 5);
string brava = String.Format("Hello{0}", 5);
ReferenceEquals(alpha, brava).Dump();
String.IsInterned(alpha).Dump();
String.IsInterned(brava).Dump();
alpha = "hello";
brava = "hello";
ReferenceEquals(alpha, brava).Dump();
}
And here are the results from the Dump() calls:
False
Hello5
Hello5
True
I would have expected both the first and last ReferenceEquals to be True. What happened?
Besides the example above, in what other cases would the ReferenceEquals fail? For example, multi-threading?
This issue is important if, for example, I’m using string parameters passed into a method as the object upon which a lock is taken. The references better be the same in that case!!!
This blog entry explains why.
In short, if your string isn’t allocated through
ldstr(i.e. it’s not a string literal defined within your code), it doesn’t end up in the (hash) table of interned strings, and therefore interning doesn’t occur.The solution is to call
String.Intern(str). The Intern method uses the intern pool to search for a string equal to the value ofstr. If such a string exists, its reference in the intern pool is returned. If the string does not exist, a reference to str is added to the intern pool, then that reference is returned.Don’t lock on strings, especially if you’re attempting to use two different reference variables to attempt to point to the same (possibly) interned string.
Also note that there are some disadvantages to interning strings. Because string literals are not expected to change during the program’s lifetime, interned strings are not garbage collected until your program exits.