2014-04-23 23 views
8

在下面這個例子中,第三個評估返回false,一切正常,但第四個例子返回true ..
我不太明白這是如何工作的,但默認Object.Equals比較兩個對象的引用平等和看到ab都指向一個字符串的唯一實例,這應該返回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/etc),即使變量(/表達式)類型爲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的類都會自動覆蓋原始的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