The clue is the words "by default". string
overrides object.Equals
with a custom implementation. Since object.Equals
is a polymorphic method (virtual
/ override
/ etc), the most-derived implementation gets used even if the variable (/expression) type is object
.
==
, however, is not polymorphic; the implementation used depends entirely on the variable (/expression) type. In this case, since the known type is object
, the only comparison available is reference equality.
Perhaps more succinctly:
class Foo {
public override string ToString() { return "hi"; }
}
//...
object obj = new Foo();
string s = obj.ToString(); // this is "hi"
This is the same principle: the most derived overload of a virtual method is used, regardless of the type that the compiler knows about (object
in this case).