在 c# 中 object 是所有類的基類,所有的結構和類都直接或間接的派生自它。前面這段話可以說所有的 c# 開發人員都知道,但是我相信其中有一部分程式設計師並不清楚甚至不知道我們常用的tostring、equals和gethashcode虛方法都來自於 object 類,並且我們可以對它們進行重寫。重寫這三個虛方法可以說在專案開發中經常用到,只不過大部分開發人員並未留意這三個虛方法可以重寫,而是自己寫方法來實現。下面我就來具體講解一下它們三個應該怎麼重寫。在這裡我需要說明的是本篇文章會大量涉及到設計規範和設計要求,**只是作為輔助理解的形式出現,因此文章中的所有**將會以**段的形式出現。
tostring 重寫是這三種方法中重寫最簡單的,也是最常用的。但是有一部分開發人員認為重寫 tostring 方法意義不大,那麼我在這裡要說的是這種想法是錯誤的。當我們在物件上呼叫 tostring 時預設返回的是類的完全限定名稱,比如說我們在 system.io.file 物件上呼叫這個方法,就會返回字串 system.io.file ,這個結果往往並不是我們所需要的結果並且這個結果也沒有什麼意義。例如我們在乙個 user 類中重寫 tostring 方法,每次呼叫 user.tostring() 時返回 "***今年xx歲",如果我們不重寫 tostring 方法的話就得不到我們想要的結果。因此我們必須重寫,這時我們就可以這麼寫。
public class user
public string name
public int age
public string ***
public override string tostring()
今年歲!";}}
重寫之後我們就可以得到我們想要的輸出內容了。雖然重寫 tostring 可以得到我們想要的內容,但是我們不能在任何情況下都重寫 tostring, 只有在以下三種情況下方可重寫 tostring :
**面對的終端使用者是開發人員;
需要寫入日誌;
ide除錯輸出。
在上面三種情況下重寫 tostring 我們還需要遵循一些設計規範,這些設計規範並不是微軟所定義的,而是開發人員在開發過程中總結出來的:
tostring 返回的字串長度應該簡短,內容描述應該清晰;
不要從 tostring 方法中返回 「」,而要返回 null ;
不要再 tostring 方法中引發並丟擲異常,針對異常應該及時捕獲並處理;
如果返回值存在地域文化(比如語言)或存在格式化要求,那麼就必須重寫 tostring 方法;
tostring 重寫後必須返回獨一無二的字串來標識例項物件。
到這裡為止我們講解完了 tostring 重寫的方法以及規則。相對來說 tostring 方法重寫是 object 虛方法重寫中十分簡單的部分,作為開發人員只需按照我前面多說的規則、方法以及實際情況來重寫即可。
在 c# 中如果對兩個物件進行相等判斷,一共有兩種情況分別是:*判斷兩者的值相等或者判斷兩者的引用位址相同* 。一般情況下我們需要對值型別物件判斷值相等,對引用型別物件判斷指向位址相同。equals 就是用來對引用型別物件判斷指向位址是否相同的。對於重寫 equals 方法,很多開發人員認為易如反掌,但是在開發中往往忘記一些很重要的細節,這些細節對於程式來說至關重要,下面我將一一進行詳細講解。
同一和相等
所謂的同一指的是兩個物件如果引用的是同乙個例項,那麼我們就說這兩個物件具有同一性。在 c# 中我們可以利用 object 類或者它的派生類中的referenceequals靜態方法來判斷物件之間的同一性。但是同一只是相等的一種,因為在某些情況下兩個物件的部分值或者全部值相等但引用不同,我們也可以說它們具有相等性。下面我們來看乙個例子,這個例子通過重寫相等性來實現兩個物件的相等性。
class program
;student s2 = new student
;if (student.referenceequals(s1, s2))
else
console.read();}}
class student
public string name
public int age
public static bool referenceequals(student s1, student s2)
else}}
從上述**中我們可以看出,雖然 s1 和 s2 引用是不相等的,但是這兩個物件使用了相同的 id ,因此我們認為 id 相同的學生就是同乙個學生。這麼做可以確保資料庫中不會出現重複的錄入。
tip:只有引用型別才會可能出現引用相等的情況,對於值型別來說呼叫 referenceequals 方法永遠返回的是 false ,因為值型別轉換成 object 時是需要裝箱的,即是傳遞的兩個引數是同乙個值,也會返回 false 。equals
判斷兩個物件是否相等,可以使用 equals ,通過它可以判斷出兩個物件是否具有相同的資料。在 object 中這個方法只是呼叫了 referenceequals 方法來判斷同一性,因此在必要的時候我們必須重寫 equals 方法。一般來說重寫 equals 方法常用的步驟如下:
tip: 如果型別是密封型別,那麼第三步可以省略掉。
我們不僅需要按照上述的步驟重寫 equals 方法,還需要注意如下幾點:
在上一小節中我們也注意到在重寫 equals 過程中我們需要重寫 gethashcode 方法。 所謂 hash code 就是用來生成和物件值對應的數字,從而高效的平衡雜湊表的作用。 重寫 gethashcode 方法是比較困難的,下面我就來詳細講解一下重寫規則、方法和注意事項。重寫 gethashcode 方法需要從效能、安全方面考慮,同時也需要滿足一些要求。
效能由於雜湊碼的返回值是 int 型別,因此會出現部分物件包含的值比 int 取值範圍大的情況,這時雜湊碼就肯定會存在重複的情況,所以這時我們要保證雜湊碼的返回值盡可能的唯一。此外針對雜湊碼的演算法我們要盡可能的保證返回的雜湊碼應當在 int 型別取值範圍內平均分布。在 equals 中利用 gethashcode 方法進行短路操作時我們必須對演算法的效能進行優化,避免將型別作為字典集合中的鍵型別使用,因為這會導致頻繁的呼叫 gethashcode 方法。在設計 gethashcode 的演算法時應保證良好的平衡性,即無論雜湊表如何對雜湊值進行 bucketing,也不會破壞平衡性。一般來說最理想的狀態是兩個物件間 1 bit 的差異應該造成雜湊碼 16 bit 的差異。
安全在安全性這方面首先應該遵循的是難以偽造雜湊碼物件,一般來說攻擊者會向雜湊表中寫入大量雜湊值相同的資料,這時如果雜湊表實現效率不高將會收到拒絕服務攻擊。我們一般會向來自相關型別的雜湊碼使用異或操作,且保證運算元不相近或者相等。如果出現運算元相近或者相等的情況,那麼應該考慮使用位移和加法操作。但是多次使用 and 操作符會出現雜湊值為 0 的情況,而多次使用 or 操作符則會出現雜湊值為 1 的情況,這一點需要注意一下。更進一步的做法是,我們在開發中應該使用移位操作符來分解比 int 大的型別。
要求要求是效能和安全的基礎,只要完全符合了要求的規定,效能和安全才能很好的起作用。要求的第一點也是最基礎的優點,相等的物件它們的雜湊碼也相等,其次在特定的生命週期內,特定物件的 gethashcode 的返回值始終是一樣的,最後 gethashcode 不能引發任何異常,如果其**現異常也必須返回乙個值來表示內部出現異常。
本篇文章主要講解了重寫 object 中虛方法的知識,其中涉及到了很多 c# 核心內容,這些內容和知識在實際開發中用的很多,但是大多數開發人員並不在意,因此我希望讀者閱讀完我這篇文章後能對這些內容和知識有初步的了解。
如何重寫object虛方法
在 c 中 object 是所有類的基類,所有的結構和類都直接或間接的派生自它。前面這段話可以說所有的 c 開發人員都知道,但是我相信其中有一部分程式設計師並不清楚甚至不知道我們常用的 tostring equals 和 gethashcode 虛方法都來自於 object 類,並且我們可以對它們進...
重寫Object的equals方法
object的equals比較兩個物件是否相同,沒有重寫時比較的是記憶體位址是否相同 但我們有時候比較的是兩個物件中的屬性是否相同,重寫equals package cn.sasa.demo1 public class person public string getname public void...
點滴積累 從object中取值
很多人在程式設計中可能會遇到這樣的問題,返回乙個object物件,怎麼取其中的值 一般獲得的值都需要轉換成字串物件。如果object中只有乙個值,直接轉換就可以。多個值的情況下怎麼獲取呢?這時候就應該考慮強制轉換。然後再去取值。object objlist object object objlist...