當調用 Remove 失效時 [C#]

當調用 Remove 失效時 [C#
]




Written by Allen Lee




有沒有試過從一個集合裏面移除一個對象以後,這個集合仍然留有這個對象?世界之大,無奇不有。稍有疏忽,便會致使這種奇怪的現象。如今讓咱們看看這個「不死」對象到底是怎麼一回事。

一、「不死」對象現身


這個問題起初是我一個同事提出的,爲了重現「不死」對象,現把代碼簡化以下:
//Code#01 IListproducts=newListProduct(); products.Add(GetProduct("1412")); products.Remove(GetProduct("1412"));
其中 Product 類代碼以下:
//Code#02 classProduct { publicProduct(stringid) { m_ID=id; } privatestringm_ID; publicstringID { get {returnm_ID;} } publicoverridestringToString() { return"ID:"+m_ID; } }
而 GetProduct 方法則根據傳入的 ID 從數據庫讀取數據並返回,它的簽名以下:
//Code#03 publicstaticProductGetProduct(stringid);
要想知道編號爲 1412 的對象是否從 products 中移除,只需在 Code #01 的最後加上這樣一行:
//Code#04 Console.WriteLine(products.Count); 二、一不當心掉進陷阱 不知道你有沒有查看 SDK 的習慣,其實 SDK 裏面蘊藏着不少對咱們解決問題有啓發做用的信息的。如今讓咱們看看 SDK 裏面可否找到什麼蛛絲馬跡。 因爲 products 的真身是 ListT,因此咱們有必要看看 ListT 是如何實現 IList.Remove 的: This method determines equality using the default equality comparer EqualityComparer.Default for T, the type of values in the list. 原來,ListT 在 IList.Remove 中使用 EqualityComparer.Default 來判斷兩個對象是否相等。那麼 EqualityComparer.Default 又是如何得知兩個對象是否相等呢? The Default property checks whether type T implements the System.IEquatable generic interface and if so returns an EqualityComparer that uses that implementation. Otherwise it returns an EqualityComparer that uses the overrides of Object.Equals and Object.GetHashCode provided by T. 把上面這段話結合 Code #02 來看,咱們能夠發現 ListT 中的 IList.Remove 判斷兩個 Product 對象是否相等的方法是從 Object 根類繼承下來的 Equals 和 GetHashCode 方法,即比較兩個對象的引用是否指向同一個對象。 因爲 GetProduct 方法每次返回的都是一個新的對象(暫時讓咱們忘記對象緩存這傢伙),因而就致使了集合裏面出現「不死」對象。 三、不要被同一顆×××打中兩次 「不要被同一顆×××打中兩次」原意是指同一個錯誤不要兩次犯,這句話暗含着對兩個表示錯誤的對象進行邏輯上的判等,就像上面須要判斷兩個 Product 的對象在邏輯上是否相等那樣。 至此,咱們也知道了令 Remove 從新生效的兩個可選辦法是: 讓 Product 類實現 IEquatableT 接口; 爲 Product 類重寫 Equals 和 GetHashCode 方法。 在大多數狀況下,咱們但願比較的並非對象的引用,而是對象的內容,與此同時,咱們又不太可能爲了這些小對象勞師動衆地實現對象緩存,因而,你就頗有可能在相似的代碼中邂逅「不死」對象了。
相關文章
相關標籤/搜索