Is the string == overloaded operator actually used in some generic comparison method?

I am currently reading Jon Skeet's C# in Depth, 2nd Edition. I'd like to quote listing 3.5:

static bool AreReferencesEqual<T>(T first, T second) where T : class
{
    return first == second;
}
...
string name = "John";
string intro1 = "My name is " + name;
string intro2 = "My name is " + name;
Console.WriteLine(intro1 == intro2);
Console.WriteLine(AreReferencesEqual(intro1, intro2);

The author writes that the output should be True for the first comparison and False for the second one, because the overloaded operator is not used in the generic method. And he is, of course, right about the output.

Now let's change the code snippet a little bit:

static bool AreReferencesEqual<T>(T first, T second) where T : class
{
    return first == second;
}
...
string intro1 = "John";
string intro2 = "John";
Console.WriteLine(intro1 == intro2);
Console.WriteLine(AreReferencesEqual(intro1, intro2);

Now both methods of comparing return True. Let's tweak the code again, because this might have something to do with the fact that previously we compared variables that were created using an already existing string.

static bool AreReferencesEqual<T>(T first, T second) where T : class
{
    return first == second;
}
...
string name = "John"
string intro1 = name;
string intro2 = name;
Console.WriteLine(intro1 == intro2);
Console.WriteLine(AreReferencesEqual(intro1, intro2);

The output is True in both situations.

Can anyone clarify what are the reasons for such behavior? Is there really such big of a difference between examples one and three?

Jon Skeet
people
quotationmark

Yes, there's a massive difference.

In example 1, intro1 and intro2 refer to different objects. In examples 2 and 3, intro1 and intro2 have the same value - they refer to the same object, so if you call Object.ReferenceEquals(intro1, intro2) that will return true.

The reason for the behaviour is that the compiler has to work out what == means in AreReferencesEqual at compile-time, without knowing the value of T. It can't tell that you're going to call it with a type argument of string, so it doesn't know about the overload of ==. It's basically the same reason you couldn't call any other string-specific members in AreReferencesEqual.

people

See more on this question at Stackoverflow