2014-01-14 417 views
69

爲什麼這段代碼返回true:爲什麼這兩個比較有不同的結果?

new Byte() == new Byte() // returns true 

但是這個代碼返回false:

new Byte[0] == new Byte[0] // returns false 
+12

見http://ericlippert.com/2014/01/15/inconsistent-equality/ –

+4

我很驚訝沒有人發現這個問題的重複,因爲它是非常基本的**價值**類型詩句**參考* *輸入問題。 – P5Coder

+2

我更加驚訝於它得到的票數 - 51現在。 – P5Coder

回答

143

因爲new Byte()默認創建值類型,這是按值進行比較(它將返回byte與價值0 )。和new Byte[0]創建數組,這是一個引用類型,並通過引用進行比較(並且這兩個數組的實例將具有不同的引用)。

查看Value Types and Reference Types文章的詳細信息。

44

.NET中的字節數爲value types,這意味着當且僅當兩個字節具有相同的值時==運算符才返回true。這也被稱爲value equality

但是.NET中的數組是reference types,這意味着==運算符返回true,當且僅當它們引用內存中的同一個數組實例時。這也被稱爲reference equality or identity

請注意,==運算符可以針對參考和值類型進行重載。例如,System.String是引用類型,但字符串的==運算符按順序比較數組中的每個字符。見Guidelines for Overloading Equals() and Operator == (C# Programming Guide)

如果你想測試陣列是否含有完全相同的值(按順序),你應該考慮使用Enumerable.SequenceEqual代替==

+1

我認爲問題的關鍵是關於'=='運算符及其雙重性質。這個答案明顯涵蓋了這一點 –

+1

最正確的答案,如果只用於「默認」 –

+0

我喜歡對其他引用類型使用「默認」,但實際上是否可以更改數組類型的此行爲? –

10

比較引用實際上是比較指針地址,它們是不同的,即返回false和value地址的原因不管它比較值。

編譯器嘗試將值類型存儲在寄存器中,但由於寄存器編號有限,所以在堆棧中進一步存儲的值爲[Reference],而引用類型在堆棧中,但值在Heap中保存存儲器地址的地址。

這裏的比較比較堆棧中存在的值,在第一種情況下它們是相同的,而在第二種情況下,它是不同的堆地址。

reference

+5

這是一個相當混亂的答案。第一部分仍然使它看起來像參考比較,因爲您仍然使用「指針」一詞。使用圖形而不僅僅是文本也很煩人,因爲它使我很難編輯它以改善答案。 –

+0

-1用於延續「值類型被存儲在堆棧中」的神話。我認爲這兩個「新的Byte()」調用的結果很可能存儲在寄存器中。 –

+0

@Damien_The_Unbeliever註冊存儲取決於寄存器的可用性,否則它存儲在堆棧中,在這兩種情況下,值都是相同的。 –

1

還有就是==操作者,其中兩個操作數都是byte類型的過載和它被實現爲比較每個字節的值;在這種情況下,你有兩個零字節,它們是相等的。

==操作者不超載爲陣列,因此使用具有兩個操作數object過載(因爲數組是object類型的)在第二種情況下,其實現比較兩個對象的引用。對兩個數組的引用是不同的。

值得注意的是,這與byte是一個值類型並且數組是引用類型的事實沒有任何關係(直接)。byte==運算符具有值語義而只有,因爲運算符在該實現中存在特定的重載。如果超負荷不存在,那麼沒有超載,其中兩個字節將是有效的操作數,因此代碼根本不會編譯。您可以通過創建自定義struct並將其與==運算符的兩個實例進行比較來輕鬆查看。代碼不會編譯,除非您爲這些類型提供您自己的==實現。

相關問題