Есть несколько вещей, происходящих.Во-первых, в этом примере:
string s1 = "a";
string s2 = "a";
Console.WriteLine(s1 == s2);
Вы утверждаете, что:
Обе являются разными ссылками на объект.
Это не так из-за интернирование строк .s1
и s2
являются ссылками на один и тот же объект.Спецификация C # гарантирует, что - из раздела 2.4.4.5 спецификации C # 4:
Когда два или более строковых литерала, которые эквивалентны в соответствии с оператором равенства строк (§7.10.7), появляются вВ той же программе эти строковые литералы ссылаются на один и тот же экземпляр строки.
Таким образом, в этом конкретном случае вы все равно получите «true», даже если вы напечатаете object.ReferenceEquals(s1, s2)
, или если вы сделали это, используя сравнение истинных опорных идентификаторов с ==
:
object s1 = "a";
object s2 = "a";
Console.WriteLine(s1 == s2); // Still prints True due to string literal interning
Однако, даже если эти были ссылками на отдельные объекты, ==
является перегруженным для string
.Перегрузка является решением времени компиляции - используемая реализация зависит от типов операндов времени компиляции.Например:
string a = new string('x', 1);
string b = new string('x', 1);
Console.WriteLine(a == b); // Uses string's implementation, prints True
object c = a;
object d = b;
Console.WriteLine(c == d); // Reference identity comparison, prints False
Сравните это с object.Equals(object)
, который является виртуальным методом.Как это бывает, String
перегружает этот метод , а также , но важно, что он переопределяет его.Поэтому, если мы изменим наш код на:
string a = new string('x', 1);
string b = new string('x', 1);
Console.WriteLine(a.Equals((object) b));
object c = a;
object d = b;
Console.WriteLine(c.Equals(d));
..., тогда оба вызова метода в скомпилированном коде будут просто равны object.Equals(object)
, но они будут все еще , и оба выведут Trueиз-за полиморфизма: будет использоваться реализация в String
.
Вот как будет выглядеть вызов перегруженного метода :
string a = new string('x', 1);
string b = new string('x', 1);
Console.WriteLine(a.Equals(b)); // Calls string.Equals(string)