2015-12-25 31 views
6

在C#中嘗試實現一個簡單的單向鏈表時,我注意到==在比較兩個用int值裝箱的對象類型變量時不起作用但.Equals的作品。爲什麼在比較兩個使用相同int值的對象類型變量時,==不起作用

想要檢查爲什麼是這樣。

以下代碼段是一個通用的對象類型的數據屬性

public class Node { 
    /// <summary> 
    /// Data contained in the node 
    /// </summary> 
    private object Data { get; set; }; 
} 

下面的代碼遍歷類型對象的值的單向鏈表和搜索 -

/// <summary> 
/// <param name="d">Data to be searched in all the nodes of a singly linked list 
/// Traverses through each node of a singly linked list and searches for an element 
/// <returns>Node if the searched element exists else null </returns> 
public Node Search(object d) 
{ 
    Node temp = head; 

    while (temp != null) 
    { 
     if (temp.Data.Equals(d)) 
     { 
      return temp; 
     } 

     temp = temp.Next; 
    } 

    return null; 
} 

但是,如果我更換

temp.Data.Equals(d) 

與 temp.Data == d

它停止工作,即使temp.Datad都具有值'3'。 ==不適用於對象類型變量的任何原因?

下面是來自主要功能的片段 -

SinglyLinkedList list = new SinglyLinkedList(); 
list.Insert(1); 
list.Insert(2); 
list.Insert(3); 
list.Insert(4); 
list.Insert(5); 

list.Print(); 

Node mid = list.Search(3); 

我相信,因爲我傳遞一個int值3和搜索方法需要一個對象類型,它已成功地將盒裝3作爲對象類型。然而,不知道爲什麼==不起作用,但.Equals呢。

==運算符僅爲值類型重載?

+3

您應該使用泛型。 – SLaks

+0

是的,這只是爲了實踐目的。我意識到泛型將已經有一個LinkedList實現 – Ankit

回答

9

有兩個原因:

  • Equals不與==,反之亦然界,默認情況下檢查引用相等:

    正如你可以在.Equals vs ==規格如下:

    默認情況下,運營商==測試參考平等通過確定兩個引用是否指示相同對象,因此引用類型不需要實現運算符==以獲得此功能。當一個類型是不可變的,意味着包含在實例中的數據不能被改變,重載運算符==來比較值相等而不是引用相等可以是有用的,因爲作爲不可變對象,只要它們具有相同的值。不建議在非不可變類型中覆蓋運算符==

    重載運算符==實現不應該拋出異常。任何超載運營商==的類型也應該使運營商!=過載。

    雖然編譯器將拋出一個錯誤,如果你不重寫!=爲好,並警告說,你最好同時覆蓋.Equals.GetHashCode

    因此,重寫/重載.Equals==!=是不同的事情。覆蓋.Equals對超載==!=沒有影響。畢竟==是一個自定義操作符。儘管這樣做不明智,但您可以將其用於除平等檢查之外的其他目的。

  • 而且運營商都在編譯時解決:

    看看下面的例子以下csharp交互shell程序:

    $ csharp 
    Mono C# Shell, type "help;" for help 
    
    Enter statements below. 
    csharp> public class Foo { 
         > 
         > public int data; 
         > 
         > public static bool operator == (Foo f1, Foo f2) { 
         >  return f1.data == f2.data; 
         > } 
         > 
         > public static bool operator != (Foo f1, Foo f2) { 
         > 
         >  return f1.data != f2.data; 
         > } 
         > 
         > } 
    (1,15): warning CS0660: `Foo' defines operator == or operator != but does not override Object.Equals(object o) 
    (1,15): warning CS0661: `Foo' defines operator == or operator != but does not override Object.GetHashCode() 
    csharp> object f = new Foo(); 
    csharp> object f2 = new Foo(); 
    csharp> f == f2 
    false 
    csharp> Foo f3 = f as Foo; 
    csharp> Foo f4 = f2 as Foo; 
    csharp> f3 == f4 
    true 
    

    正如你所看到的,==給出了不同的結果,如果你請將對象稱爲objectFoo。由於您使用的是object,因此C#編譯時唯一的綁定可以是引用相等的綁定。

+0

很酷的解釋。感謝您舉例說明如何覆蓋==和!=來調整引用等於比較值。 – Ankit

+1

@Ankit不,你不能重載操作符。你只能重載它們。請注意,'int'確實會超載'=='。這裏的關鍵是靜態(編譯時)類型,這很重要,因爲這是一個重載而不是覆蓋。 – phoog

+0

感謝您的評論@phoog。閱讀你的評論,然後這[鏈接](http://geekswithblogs.net/BlackRabbitCoder/archive/2011/07/07/c.net-little-pitfalls-operators-are-overloaded-not-overridden.aspx)讓我理解運算符在編譯時確實被重載和綁定,並且不會因爲它們是靜態的而被覆蓋。該鏈接指出了操作符重寫的一種解決方法 - 在重載操作符內使用虛擬方法,然後可以重寫虛擬方法:) – Ankit

5

這是因爲System.Object實施==測試引用相等,像靜態Equals(object, object),而實例Equals(object)超載,所以它檢查的實際值。

當您將一個值類型放入兩次時,會得到兩個不同的實例,所以當然引用相等失敗。

運算符是靜態的,在編譯時綁定,所以沒有動態分派。即使使用已經是引用類型的字符串,因此在分配給對象類型變量時未將其裝箱,如果其中一個操作數具有除string以外的其他靜態類型,則可以使用==運算符進行非預期的引用比較。

+0

@ user2864740好點,謝謝。編輯。 – phoog

+0

謝謝。是的,'=='所做的引用相等檢查是無意的。我會在將來爲字符串記住這一點。 – Ankit

4

運算符==就像基於編譯時類型選擇的重載靜態函數。在你的情況下,值的類型是Object,其中==運算符實現引用相等。

另一方面,.Equals是虛擬的和重寫的,所以它會根據實際類型進行比較。

+0

對。感謝@hege_hegedus編輯問題並讓我知道'=='實現引用等同於'.Equals',它是虛擬的並且被覆蓋,因此比較了實際的類型。 – Ankit

相關問題