2009-10-18 56 views
2

我應該從下面的結果中對Equals(),ReferenceEquals()和==做出什麼決定?他們生產什麼?Value vs Reference

#region 
int integer = 1; 
int integer2 = integer; 

bool referenceEquality = (integer == integer2);//true 
bool valueEquality = integer.Equals(integer2);//true 
bool valueEqualityMore = object.Equals(integer, integer2);//true 
bool valueEqualityMoreMore = object.ReferenceEquals(integer, integer2);//false 
#endregion 

#region 
int integer = 1; 
int integer2 = 1; 

bool referenceEquality = (integer == integer2);//true 
bool valueEquality = integer.Equals(integer2);//true 
bool valueEqualityMore = object.Equals(integer, integer2);//true 
bool valueEqualityMoreMore = object.ReferenceEquals(integer, integer2);//false 
#endregion 

#region 
MyClass obj = new MyClass(1, "Hello"); 
MyClass obj2 = obj; 

bool referenceEquality = (obj == obj2);//true 
bool valueEquality = obj.Equals(obj2);//true 
bool valueEqualityMore = object.Equals(obj, obj2);//true 
bool valueEqualityMoreMore = object.ReferenceEquals(obj, obj2);//true    
#endregion 

#region 
MyClass obj = new MyClass(1, "Hello"); 
MyClass obj2 = new MyClass(1, "Hello"); 

bool referenceEquality = (obj == obj2);//false 
bool valueEquality = obj.Equals(obj2);//false 
bool valueEqualityMore = object.Equals(obj, obj2);//false 
bool valueEqualityMoreMore = object.ReferenceEquals(obj, obj2);//false 
#endregion 

地獄!我一點都沒懂。

對我來說,第一個block的referenceEquals()應該返回true。 ==在第二個塊中應該返回false(因爲引用是不同的)。 而且,第四塊中的兩個Equals()應該返回true(因爲它們的值相同)。

+1

您可以縮小你的問題,具體如下: 1)這些結果你發現令人驚訝的 2)你在說什麼決定 – Mathias 2009-10-18 16:09:58

+0

好評。查看更新。 – anonymous 2009-10-18 16:13:37

+1

referenceEquals比較對象實例引用,因爲int值是對兩個不同對象的框,它們具有不同的引用。 ==默認情況下比較引用,所以即使具有相同狀態的MyClass的兩個實例也具有不同的引用,因爲它們是兩個不同的對象。 – Elisha 2009-10-18 16:19:31

回答

8

您似乎遇到的第一個混淆之處在於,對於值類型,即int,float,DateTime==運算符是值相等。對於引用類型,==是(默認情況下,請參見下文)引用相等。這可以解釋前兩個整數情況下答案的不一致性。

其次,默認實現Equals()測試引用相等,而不是值相等。因此,MyClass似乎不會覆蓋Equals(),這解釋了您的參考案例之間的答案不一致。

此外,許多參考類型(例如String)會覆蓋==運算符以提供值相等的語義。所以你最好的選擇,直到你記住哪些類型是哪一個,就是查找文檔。

簡而言之:

  • 值類型
    • ==是值相等(對於框架類型)
    • 不是引用類型,所以引用相等是無意義
  • 參考類型
    • ReferenceEquals()總是引用相等
    • ==是默認參考平等,但可以是(並且通常是用於骨架類型)覆蓋,以提供值相等
    • Equals()是默認參考平等,但可以是(並且通常是爲框架型)重寫以提供值相等
+0

所有這一切的一個很好的更新可以在這裏找到:http:// stackoverflow .com/questions/384294/where-the-implementation-of-internalequalsobject-obja-object-objb,它展示了C++代碼的內幕。基本上,它明確表明值類型被「Equals」特別對待。 – Abel 2009-10-18 16:27:27

1

ReferenceEquals兩個對象是相同的,如果它們指向存儲器中的同一個地方。對於兩種不同的值類型,情況從來就不是這樣。

Equals如果等於覆蓋認爲它們相等,則兩個對象相等。這通常意味着如果ReferenceEqual將返回true,並且這些屬性返回true。每個對象或結構對於Equals的行爲往往不同。 注意:每個內置值類型(int,double,IntPtr)已被重寫Equals,這就是爲什麼它對值類型(比較內容)和ReferenceEquals(比較地址)有所不同。

==返回true,如果兩個對象具有相同的引用,或如果兩個值類型具有相同的內容。盒裝值類型在進行比較之前先進行拆箱,然後將它們明確地轉換爲對象。

請注意,您的new MyClass(...)返回虛假Equals。這是因爲MyClass的執行沒有覆蓋Equals方法。結果:它的行爲與ReferenceEquals相同。

更新:在Equals值類型

+0

整數ReferenceEquals()發生了什麼? – anonymous 2009-10-18 16:09:28

+0

而且,爲什麼int整數= 1; int integer2 = 1; bool referenceEquality =(integer == integer2); // true – anonymous 2009-10-18 16:10:22

+0

== ==直接調用'ReferenceEquals'的行爲不同。對於值類型,其行爲與調用「Equals」相同。 – Abel 2009-10-18 16:13:41

1

ReferenceEquals檢查補充說明,如果兩個對象引用指向同一對象。也就是說,他們指向內存中的相同位置。

Equals是一個虛擬的方法,所以它可能在實踐中被重寫做任何事情。然而,該方法的目的是以某種對於類型有意義的方式比較實例,無論採用何種方式。如果Equals未被覆蓋,則使用object.Equals的實現,其相當於ReferenceEquals

== 是相等運算符,默認情況下,它爲引用類型(即類,盒裝值類型,接口)和值類型實例(即結構體)比較引用相等性和值相等(字段值相同) 。 ==可能被重載以提供自定義行爲,但它不是虛擬的,如Equals

通過它傳遞給像ReferenceEquals的方法,其具有object參數,盒int,產生與內部的整數的堆中的對象使用一個int作爲object,例如。基本上是指object.ReferenceEquals((object)integer1, (object)integer2)

通過引用相等(ReferenceEquals==)相同的整數的不同盒裝實例比較將給false,而值相等(Equals)會給true。對於未裝箱的相同整數(值類型),==Equals都比較值相等,因此會給出true

1

默認情況下,當用作a==b時,operator==的行爲如下。請注意,operator==可以被覆蓋以執行任何操作。

  • 如果a是值類型,則編譯爲a.Equals(b)
  • 如果a是引用類型,則編譯爲object.Equals(a,b)

object.Equals(a, b)只在引用類型進行操作,並執行以下操作:

  • 如果anull,然後返回(b==null)
  • 否則調用a.Equals(b)

object.ReferenceEquals(a, b)只在引用類型進行操作。 C#/ .NET中的對象引用在內部保存爲指針。如果引用ab是相同的,也就是說,如果它們在內部指向同一對象,則此方法返回true。

數值類型以兩種形式存在:unboxed盒裝。在下列情況下討論值類型,我會使用以下變量:

int unboxed = 3; 
// boxing occurs automatically when a value type is cast to object or 
// to an interface. This allocates memory on the heap to store the value 
// and places a reference (internally a pointer) to this memory in boxed. 
object boxed = unboxed; 

在這一點上,boxed表現爲引用類型。兩個裝箱值可能不在內存中的相同位置,如您在撥打object.ReferenceEquals(integer1, integer2)時看到的那樣(由於將每個參數轉換爲object而發生自動裝箱)。當您撥打object.Equals(integer1, integer2)時,這些值將被裝箱,但由於BOX的形式爲integer1不爲空,因此呼叫的行爲類似於integer1.Equals((object)integer2),由於裝箱值均爲1,所以返回true。 (請參閱下面關於爲什麼我在這裏手動投射的註釋)。

注意的手動投以上:System.Int32,與大多數其他值類型一起,有一個方法Int32.Equals(Int32 other),因此調用integer1.Equals(integer2)不會箱integer2值。這對輕量級值類型的性能有很大(正面)影響。

1

我對所做的實際比較做了更正。我爲所有情況添加了相同的比較,因爲您只對整數(使用==運算符)進行.Equals(int),而對其他類型不使用.Equals(object)。我還添加了明確鑄件的參數顯示,通過使用它們作爲參數,其隱含的鑄件所引起:

int integer = 1; 
int integer2 = 1; // exactly the same result as copying integer 

bool valueEquality = (integer == integer2); //true 
bool valueEquality2 = integer.Equals(integer2); //true 
bool typeAndValueEquality = integer.Equals((object)integer2); //true 
bool typeAndValueEquality2 = object.Equals((object)integer, (object)integer2); //true 
bool referenceEquality = object.ReferenceEquals((object)integer, (object)integer2); //false 

// 

MyClass obj = new MyClass(1, "Hello"); 
MyClass obj2 = obj; 

bool referenceEquality = (obj == obj2); //true 
bool referenceEquality2 = obj.Equals((object)obj2); //true 
bool typeAndReferenceEquality = object.Equals((object)obj, (object)obj2); //true 
bool referenceEquality3 = object.ReferenceEquals((object)obj, (object)obj2); //true 

// 

MyClass obj = new MyClass(1, "Hello"); 
MyClass obj2 = new MyClass(1, "Hello"); 

bool referenceEquality = (obj == obj2); //false 
bool referenceEquality2 = obj.Equals((object)obj2); //false 
bool typeAndReferenceEquality = object.Equals((object)obj, (object)obj2); //false 
bool referenceEquality = object.ReferenceEquals((object)obj, (object)obj2); //false 
+0

@Guffa,非常好。如果您之前發佈過此消息,我已經接受了您的答案。 – anonymous 2009-10-19 09:43:37