The first case compares 2 references to the same object (String.Empty
). Calling operator==
for 2 object
variables causes their comparance by reference and gives true
.
The second case produces 2 different instances of string class. Their reference comparison gives false
If you give string
type to x
and y
in the second case the string.operator==
override will be called and the comparison gives true
Note that we don't deal with the string interning directly in both cases. The string objects which we compare are created using string(char[])
constructor. Apparently that constructor is designed to return the value of the string.Empty
field when called with an empty array as an argument.
The answer posted by MarcinJuraszek referes to the Lippert's blog which discusses string interning. That blog post discusses other corner case of string class usage. Consider this example from the forementioned Lippert's blog:
object obj = "";
string str1 = "";
string str2 = String.Empty;
Console.WriteLine(obj == str1); // true
Console.WriteLine(str1 == str2); // true
Console.WriteLine(obj == str2); // sometimes true, sometimes false?!
What we see here is that the assignment from the empty string literal (""
) is not guaranteed to produce the reference to the static readonly System.String.Empty
field.
Let's look at the IL for the object x = new string("".ToArray());
expression:
IL_0001: ldstr ""
IL_0006: call !!0[] [System.Core]System.Linq.Enumerable::ToArray<char>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>)
IL_000b: newobj instance void [mscorlib]System.String::.ctor(char[])
IL_0010: stloc.0
The interning may (or may not) happen at the IL_0001 line. Whether the literal is interned or not, the ToArray()
method produces a new empty array and the String::.ctor(char[])
gives us String.Empty
.
What we see here is not the special case of string.Empty
but rather is one of the side effects of the string
class being reference type and immutable at the same time. There are other immutable framework types which have predefined values with similar semantics (like DateTime.MinValue
). But as far as I know such framework types are defined as struct
unlike the string
which is a reference type. The value types are totally different story... It does not make sense to return some fixed predefined type instance from a mutable class constructor (the calling code will be able to change that instance and cause the unpredictable behavior of the type). So the reference types whose constructors do not always return new instances may exist provided that those types are immutable. I am not aware of other such types in the framework though, except the string
.