2014-04-23 3 views
8

В этом примере третий результат возвращает false, все хорошо, но четвертый пример возвращает true.
Я не совсем понимаю, как это работает, по умолчанию Object.Equals сравнивает две ссылки для объекта равенство и видя, как a и b оба указывают на уникальный экземпляр строки, это должно возвращать значение false, которое оно делает в третьем примере, но не в четвертом.
Теперь я понимаю, почему он возвращает true во втором примере, поскольку метод .Equals() переопределяется в классе строк, но в четвертом примере мы выставляем эту строку как объект.
Так он бы не назвал Object.Equals в этом случае?Переопределение равных и тип литья

static void Main() 
{ 
    // Create two equal but distinct strings 
    string a = new string(new char[] {'h', 'e', 'l', 'l', 'o'}); 
    string b = new string(new char[] {'h', 'e', 'l', 'l', 'o'}); 

    Console.WriteLine (a == b); // Returns true 
    Console.WriteLine (a.Equals(b)); // Returns true 

    // Now let's see what happens with the same tests but 
    // with variables of type object 
    object c = a; 
    object d = b; 

    Console.WriteLine (c == d); // Returns false 
    Console.WriteLine (c.Equals(d)); // Returns true 
} 

ответ

10

разгадка слова «по умолчанию». string переопределяет object.Equals с пользовательской реализацией. Поскольку object.Equals является полиморфным методом (virtual/override/и т. Д.), Наиболее производная реализация используется, даже если тип переменной (/ выражение) равен object.

==, однако не полиморфный; используемая реализация полностью зависит от типа переменной (/ выражения). В этом случае, поскольку известный тип равен object, единственным доступным сравнением является ссылочное равенство.

Возможно, более кратко:

class Foo { 
    public override string ToString() { return "hi"; } 
} 
//... 
object obj = new Foo(); 
string s = obj.ToString(); // this is "hi" 

Это тот же самый принцип: наиболее получена перегрузка виртуального метода используется, независимо от типа, что компилятор знает о (object в данном случае).

+1

Правильно, поэтому, даже если мы передадим строку объекту, она все равно вызовет переопределенную реализацию '.Equals'? –

+0

@OverlyExcessive yes; это ключевой момент полиморфизма; акцент: такие операторы, как '==', являются ** не ** полиморфными –

0

Поскольку Equals является виртуальным методом, любой класс, который реализует equals, автоматически переопределяет исходное значение независимо от того, что. Если вы хотите использовать object.Equals, вы должны использовать object.ReferenceEquals(a,b).

Для получения дополнительной информации смотрите в как виртуальный методы работы, и если вы чувствуете к ней, как виртуальные таблицы фактически реализованы (что на самом деле довольно легко, как только вы получите повесить его)

1

Equals метод является виртуальным, это означает, что даже если он вызывается по ссылке с типом object, он в конечном итоге вызовет реализацию для конкретного типа экземпляра.

Из сгенерированного IL: a.Equals(b) становится

IL_003C: ldloc.0  // a 
IL_003D: ldloc.1  // b 
IL_003E: callvirt System.String.Equals 

и c.Equals(d) становится

IL_0057: ldloc.2  // c 
IL_0058: ldloc.3  // d 
IL_0059: callvirt System.Object.Equals 

Так как виртуальные вызовы на ссылки типа строки и объекта, соответственно, и оба вызова Equals метод, а не ссылку, а на сам экземпляр.

С другой стороны, a==b становится вызов статического метода System.String.op_Equality

IL_002F: ldloc.0  // a 
IL_0030: ldloc.1  // b 
IL_0031: call  System.String.op_Equality 

в то время как c==d становится просто

IL_004D: ldloc.2  // c 
IL_004E: ldloc.3  // d 
IL_004F: ceq  

, вызов к check-equal инструкции IL, что делает только простую ссылку проверка.


Вы также можете проверить, что переопределенная реализация вызывается с кодом, как:

class MyClass 
{ 
    public override bool Equals(object obj) 
    { 
     Console.WriteLine("My Class Equals is called"); 
     return true; 
    } 
} 

void Main() 
{ 
    object a = new MyClass(); 
    object b = new MyClass(); 
    Console.WriteLine (a.Equals(b)); 
} 

Это будет выход

My Class Equals is called 
True 
Смежные вопросы