Effective C# Item27:避免ICloneable介面

來源:互聯網
上載者:User

    一般情況下,我們不建議針對類型實現ICloneable介面。因為如果一個類型支援ICloneable介面,那麼該類型的所有衍生類別都必須實現它,而且類型中所有成員類型也都要實現ICloneable介面,或者有其他建立複製對象的機制,當我們設計的類型包含交織成網狀的對象時,支援深複製會變得比較複雜。

    複製操作分為淺複製和深複製兩種,其中淺複製是指新對象包含所有成員變數的副本,如果成員變數為參考型別,那麼新對象將和原對象引用同樣的對象;深複製中新對象也包含所有成員變數的副本,但是所有參考型別的成員變數都會被遞迴的複製。對於C#來說,內建類型,例如整型,執行深複製和淺複製的結果是相同的。

    任何只包含內建類型成員的實值型別都不需要實現ICloneable介面,一個簡單的指派陳述式要比Clone()方法效率更高,因為Clone()方法必須對傳回值進行裝箱,才能轉換成一個System.Object引用。

    而對於參考型別來說,如果參考型別需要通過實現ICloneable介面的方式來表明自身支援淺複製或者深複製,這時,該類型的衍生類別也必須實現ICloneable介面。

    來看下面的代碼。

代碼

 1 class BaseType : ICloneable
2 {
3 private string _label = "class name";
4 private int [] _values = new int [ 10 ];
5
6 public object Clone()
7 {
8 BaseType rVal = new BaseType( );
9 rVal._label = _label;
10 for( int i = 0; i < _values.Length; i++ )
11 rVal._values[ i ] = _values[ i ];
12 return rVal;
13 }
14 }
15
16  class Derived : BaseType
17 {
18 private double [] _dValues = new double[ 10 ];
19
20 static void Main( string[] args )
21 {
22 Derived d = new Derived();
23 Derived d2 = d.Clone() as Derived;
24
25 if ( d2 == null )
26 Console.WriteLine( "null" );
27 }

    上述代碼在運行後,我們會發現d2的值時null,這是因為Derived類從BaseType類繼承了Clone()方法,但是繼承來的實現對Derived類型來說是不正確的,因為它只是複製了基類,BaseType.Clone()方法建立了一個BaseType類型的對象,而不是一個Derived類型的對象。

    如果需要解決這個問題,我們可以將BaseType類中的Clone()方法聲明為abstract,這樣所有的衍生類別都必須實現這個方法。另外,我們還可以通過以下的方式來解決這個問題。

代碼

 1 class BaseType
2 {
3 private string _label;
4 private int [] _values;
5
6 protected BaseType( )
7 {
8 _label = "class name";
9 _values = new int [ 10 ];
10 }
11
12 // Used by devived values to clone
13   protected BaseType( BaseType right )
14 {
15 _label = right._label;
16 _values = right._values.Clone( ) as int[ ] ;
17 }
18 }
19
20  sealed class Derived : BaseType, ICloneable
21 {
22 private double [] _dValues = new double[ 10 ];
23
24 public Derived ( )
25 {
26 _dValues = new double [ 10 ];
27 }
28
29 // Construct a copy
30 // using the base class copy ctor
31   private Derived ( Derived right ) :
32 base ( right )
33 {
34 _dValues = right._dValues.Clone( )
35 as double[ ];
36 }
37
38 static void Main( string[] args )
39 {
40 Derived d = new Derived();
41 Derived d2 = d.Clone() as Derived;
42 if ( d2 == null )
43 Console.WriteLine( "null" );
44 }
45
46 public object Clone()
47 {
48 Derived rVal = new Derived( this );
49 return rVal;
50 }
51 }

   

    總之,對於實值型別來講,我們永遠都不需要實現ICloneable介面,使用預設的賦值操作就可以了,我們應該為那些確實需要複製操作的”葉子類“實現ICloneable介面,對於那些子類可能需要實現ICloneable介面的基類來說,我們應該為其建立一個受保護的複製建構函式。除此之外,我們應該避免實現ICloneable介面。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.