If you intend to compare object references, it's clearer do it like so:
Console.WriteLine ( object.ReferenceEquals(s1, s2 ));
rather than like this:
Console.WriteLine ( ( object ) s1 == ( object ) s3 ); // false
That said, let's rewrite your code a little:
using System;
public class Program
{
public static void Main()
{
string s1 = "Hello";
string s2 = string2();
Console.WriteLine ( object.ReferenceEquals(s1, s2 )); // true
string s3 = "Hel";
s3 = s3 + "lo";
Console.WriteLine ( object.ReferenceEquals(s1, s3 )); // false
// This is the equivalent of the line above:
Console.WriteLine ( ( object ) s1 == ( object ) s3 ); // also false
Console.WriteLine (s1 == s3); // true (comparing string contents)
s3 = string.Intern(s3);
Console.WriteLine ( object.ReferenceEquals(s1, s3 )); // now true
Console.ReadLine();
}
private static string string2()
{
return "Hello";
}
}
Ok, so the question is, "Why do the first two strings have the same reference"?
The answer to that is because the compiler keeps a table of all the strings that it has stored so far, and if a new string it encounters is already in that table, it doesn't store a new one; instead, it makes the new string reference the corresponding string that is already in its table. This is called string interning
.
The next thing to note is that if you create a new string by concatenating two strings at runtime, then that new string does NOT have the same reference as an existing string. A brand new string is created.
However if you use ==
to compare that string with another string that has a different reference but the same contents, true
will be returned. That's because string ==
compares the contents of the string.
The following line in the above code demonstrates this:
Console.WriteLine (s1, s3); // true
Finally, note that the runtime can "intern" strings, that is, use a reference to an existing string rather than a new string. However, it does not do this automatically.
You can call string.Intern()
to explicitly intern a string, as the code above shows.