C#中Equality和Identity淺析
CLR提供了可以區(qū)分類(lèi)型的Equality 和Identity能力。
Equality:如果兩個(gè)對(duì)象是相同的類(lèi)型,并且它們各自帶有相同和等值的屬性。(They are instances of the same type and if each of the fields in one object matches the values of the fields in the other object)
Equality必須滿(mǎn)足三個(gè)必要條件:reflexive, symmetrics, and transitive
reflexive: 自身相等,及a==a 是永遠(yuǎn)成立的;
symmetrics: 對(duì)象性,及a==b成立那么b==a 也成立;
transitive: 傳遞性,及a==b, b==c成立那么a==c 也成立。
Identity:兩個(gè)對(duì)象必須相等(意味著他們共享同一塊內(nèi)存區(qū)域)(The two objects have the same values. – Two objects are identical if they share an address in memory)
CLR提供了至少四種方法來(lái)判斷兩個(gè)對(duì)象的等價(jià)性:
1.Public static bool ReferenceEquals(object left, object right);
2.Public static bool Equals(object left, object right);
3.Public virtual bool Equals(object right);
4.Public static bool operator==(MyClass left, MyClass right);
ReferenceEquals方法總是用來(lái)判斷兩個(gè)對(duì)象的Identity的,不管是針對(duì)值類(lèi)型還是引用類(lèi)型。所以針對(duì)值類(lèi)型,調(diào)用該方法總是會(huì)返回false,因?yàn)橹殿?lèi)型作為這個(gè)方法的參數(shù)時(shí)會(huì)進(jìn)行裝箱操作。
靜態(tài)的Equals方法提供了判斷兩個(gè)對(duì)象的Equality能力,在其實(shí)現(xiàn)的內(nèi)部,調(diào)用了上述第三個(gè)虛擬的Equals方法。和ReferenceEquals一樣,它們已經(jīng)具備從底層判斷兩個(gè)對(duì)象的能力,我們從來(lái)不會(huì)覆寫(xiě)這兩個(gè)方法。
實(shí)例Equals方法也是用來(lái)區(qū)分兩個(gè)對(duì)象的Equality的。
對(duì)于引用類(lèi)型的對(duì)象,它和ReferenceEquals方法幾乎是一樣的。(因?yàn)榕袛鄡蓚€(gè)引用類(lèi)型是否的Equality往往從Identity上就可以區(qū)分)
而值類(lèi)型的對(duì)象,我們不僅要判斷他們具有相同的對(duì)象類(lèi)型,還要判斷他們的值相等。值類(lèi)型從System.ValueType繼承而來(lái),ValueType已經(jīng)重寫(xiě)了Object.Equals()方法,本來(lái)已經(jīng)可以用來(lái)滿(mǎn)足這些要求的。但是ValueType.Equals()方法不是很有效,因?yàn)樗仨氁ㄟ^(guò)反射,在不知道具體的派生類(lèi)型中,完成對(duì)它們所含有成員變量的值的比較。因此,建議在我們實(shí)現(xiàn)一個(gè)值類(lèi)型的數(shù)據(jù)結(jié)構(gòu)時(shí),同時(shí)重寫(xiě)ValueType.Equals()方法。
然而我們?cè)倩仡^看看引用類(lèi)型,有時(shí)兩個(gè)引用類(lèi)型的對(duì)象往往被用來(lái)進(jìn)行類(lèi)似值類(lèi)型的比較,比如:String類(lèi)型,它雖然是引用類(lèi)型,但它也重寫(xiě)了Equals方法,因?yàn)槲覀兡盟鼇?lái)判斷兩個(gè)string是否相同(Equality),實(shí)際是希望判斷它們是否具有相同的內(nèi)容,這是一個(gè)value semantics。因此,我們建議在考慮實(shí)現(xiàn)一個(gè)用作值語(yǔ)義環(huán)境下的引用類(lèi)型時(shí)候,也重寫(xiě)基類(lèi)的Object.Equals()方法。
注:請(qǐng)參考MDSN或其它相關(guān)文檔,如何實(shí)現(xiàn)Equals方法的重寫(xiě)。
上面的圖示給了很好的例子來(lái)區(qū)分Equals和ReferenceEquals方法,被用來(lái)做Equility和Identity判斷的區(qū)別。
\== 運(yùn)算符是可由類(lèi)重載的運(yùn)算符,它也是用來(lái)判斷恒等的。 對(duì)于未重載= =的引用類(lèi)型,會(huì)比較兩個(gè)引用類(lèi)型是否引用同一個(gè)對(duì)象。這跟引用類(lèi)型的Equals()方法是一樣的。
對(duì)于未重載= =的值類(lèi)型,該運(yùn)算符會(huì)比較這兩個(gè)值是否"按位"相等,即是否這兩個(gè)值中的每個(gè)字段都相等。和Equals方法一樣,推薦在自定義值類(lèi)型中,也要重載= =運(yùn)算符,因?yàn)橐泊嬖诜瓷湓谛噬系挠绊憽?/p>
\== 運(yùn)算符和Equals方法的區(qū)別在于多態(tài)表現(xiàn)上。Equals方法是重寫(xiě),而= =運(yùn)算符是被重載。這意味著除非編譯器知道調(diào)用具體的重載版本,否則它只是調(diào)用未重載的= =版本。
相關(guān)文章
C#最小二乘法擬合曲線(xiàn)成直線(xiàn)的實(shí)例
這篇文章主要介紹了C#最小二乘法擬合曲線(xiàn)成直線(xiàn)的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02C#使用有道ip地址查詢(xún)接口方法實(shí)例詳解
這篇文章主要介紹了C#使用有道ip地址查詢(xún)接口方法,實(shí)例分析了有道IP地址查詢(xún)接口的使用方法與數(shù)據(jù)返回格式,需要的朋友可以參考下2015-05-05C#使用StringBuilder實(shí)現(xiàn)高效處理字符串
這篇文章主要為大家詳細(xì)介紹了C#如何使用StringBuilder實(shí)現(xiàn)高效處理字符串,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-01-01C#字符串內(nèi)存分配與駐留池學(xué)習(xí)分享
這篇文章主要介紹了C#字符串內(nèi)存分配與駐留池學(xué)習(xí)分享,大家參考使用吧2013-12-12