.NET對象克隆的深究 選擇自 qwbyxw 的 Blog

By Manoj G

Posted 1 Aug 2003

Applied to:

VB.NET, XP, W2K, .NET 1.1, Win9X

摘要:本文討論了爲什麼需要對象的克隆,怎樣克隆以及對克隆的一些思考。

Download source files - 10 Kb

簡介

本文我將討論.NET編程中一個比較感興趣的方面——對象克隆。下面將討論對象克隆的必要性、對象克隆的方法以及關於對象克隆的一些思考。

背景

大家一定知道.NET對象是有二大類型的:  值類型和引用類型。 值類型對象的變量表示對象本身,而且具有“copy-on-assignment”的行爲。也就是說, 以下的討論不適用於值類型。 

另一方面,引用類型的變量實際上是指向堆上的內存。 因此,如果你創建了一個引用類型的變量,並且將一個已存在的對象分配給它,實際上是創建了指向堆上的相同內存的另外一個對象。本文就是討論這樣的情況:創建的一個對象的新的拷貝,並且保存在一個變量中! 

爲什麼要克隆?

我認爲當設置一個對象的狀態要付出昂貴的代價,並且又需要取得該對象的一個拷貝以便改變當前的一些狀態時,克隆就顯得十分必要。下面列舉一個剛好能體現我 剛剛所說的情況的例子。 就拿 DataTable 類來說吧。建立一個 DataTable 會包含諸如以下的操作:爲取得架構和數據而查詢數據庫、添加約束、設置主鍵等等。那麼,當需要該 DataTable 的一個新的拷貝,哪怕是對架構作極小的改變或添加新的一行記錄等等, 明智的選擇會是克隆已存在的對象再對其進行操作,而不是創建一個新的DataTable, 那樣將需要更多的時間和資源。 

克隆也廣泛應用於數組和集合,這些時候往往會多次需要已存在對象的一個拷貝。 

克隆的類型

我 們基於克隆的程度將克隆分成兩大類:“深層”克隆和“淺表”克隆。“淺表”克隆得到一個新的實例,一個與原始對象類型相同、包含值類型字段的拷貝。但是, 如果字段是引用類型的, 該引用將被拷貝, 而不是拷貝引用的對象。 因此,原始對象的引用和克隆對象的引用都指向同一個對象。另一方面, 對象的“深層”克隆包含原始對象直接或間接引用的對象的所有拷貝。下面舉例說明。

兩種克隆模式的比較

對象X引用對象A,對象A引用對象M。對象X的“淺表”克隆對象Y,同樣也引用了對象A。相對比的是,對象X的“深層”克隆對象Y,卻直接引用了對象B,並且間接引用對象N,這裏,對象B是對象A的拷貝,對象N是對象M的拷貝。

實現克隆

System.Object提供了受保護的方法 MemberwiseClone,可用來實現淺表克隆。由於該方法標記爲“受保護”級別,因此,我們只能在繼承類或該類內部才能訪問該方法。

.NET定義了一個IClonable接口,一個需要“深層”克隆而不是“淺表”克隆的類必須實現該接口。我們需要提供一個好的實現方法來達到該接口的Clone方法實現的功能。

有 許多方法可以實現“深層”克隆。一個方法是將對象串行化到內存流中,然後反串行化到一個新的對象。我們將使用一個二進制(Binary)的 Formatter類或SOAP formatter類來進行深層串行化。做一個深寫成連載長篇而刊登的 formatter 。 這個方法的問題是類和它的成員 (完整的類表) 必須被標記爲serializable,否則formatter會發生錯誤。 

反射是另外一個能達到相同目的的方法。 Amir Harel寫的一篇好文章吸引了我, 他使用該方法提供一個好的克隆實現。 這篇文章討論得非常好! 以下是鏈接:

http://www.codeproject.com/csharp/cloneimpl_class.asp

上 面討論的任何一個方法,都要求對象的成員類型能支持自我克隆,以確保“深層”克隆能成功進行。也就是說, 對象必須是可串行化的(serializable) ,或者每個獨立的成員必須提供IClonable的實現。 如果不這樣,我們根本不可能對對象進行“深層”克隆!

綜述

克隆是提供給程序員的一個很好的方法。但是, 我們應該知道什麼時候需要提供這樣的功能,而且在某些情況下,嚴格地說,對象不應該提供這一個特性。 SQLTransaction 類爲例, 就不支持克隆。這一個類代表了SQL Server數據庫的一個事務。 克隆該對象沒有任何意義,因爲我們可能不能夠理解一個數據庫的一個活動的事務的克隆! 因此,如果你認爲克隆對象的狀態會產生應用程序邏輯上的矛盾,就不需要支持克隆。

 

                                                                                           (完)

 

參看原文:An insight into cloning objects in .NET

 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章