How is the below code is printing true
?
string x = new string(new char[0]);
string y = new string(new char[0]);
Console.WriteLine(object.ReferenceEquals(x,y));
I expected this to print False
, because I expected two separate objects to be constructed and then their references compared.
This is an undocumented (as far as I'm aware) optimization in the CLR. It's very odd, but yes: the new
operator is returning the same reference from two calls.
It appears to be implemented in CoreCLR as well on Linux (and even on Mono).
The string constructor is the only example of this that I've seen, although as noted in comments you can provoke it with other constructor overloads.
I'm convinced it's an optimization in the CLR, as the IL is as you'd expect it - and moving the constructor call into a different method doesn't change things either:
using System;
public class Test
{
static void Main()
{
// Declaring as object to avoid using the == overload in string
object x = CreateString(new char[0]);
object y = CreateString(new char[0]);
object z = CreateString(new char[1]);
Console.WriteLine(x == y); // True
Console.WriteLine(x == z); // False
}
static string CreateString(char[] c)
{
return new string(c);
}
}
Now that the CLR is open source, we can find out where this is performed. It appears to be in object.cpp
- if you search for occurrences of GetEmptyString
you'll see it used in various cases when a string of length 0 is being constructed.
See more on this question at Stackoverflow