1. 程式人生 > >改善C#程序的建議1:非用ICloneable不可的理由

改善C#程序的建議1:非用ICloneable不可的理由

沒有 class 指正 -- height serial sha color opened

原文:改善C#程序的建議1:非用ICloneable不可的理由

好吧,我承認,這是一個反標題,實際的情況是:我找不到一個非用ICloneable不可的理由。事實上,接口ICloneable還會帶來誤解,因為它只有一個Clone方法。

我們都知道,對象的拷貝分為:淺拷貝和深拷貝。ICloneable僅有一個Clone方法使我們無法從命名的角度去區分到底是哪個拷貝。

淺拷貝:將對象的字段復制到副本(新的對象)中,同時將字段的值也賦值過去,但是引用類型字段只復制引用,而不是引用類型本身。這意味著,源對象引用類型字段的值改變了,會影響到副本中對應的值也改變;

深拷貝:將對象的字段復制到副本(新的對象)中,無論是值類型還是引用類型字段,都會復制類型本身及類型的值。這意味著,源對象引用類型字段的值改變了,不會影響到副本中對應的值;

於是問題來了,如果類型繼承了ICloneable接口,那麽類型中的Clone是淺拷貝還是深拷貝。微軟的解釋是:你既可以在Clone方法中實現淺拷貝,也可以實現深拷貝。那麽,為什麽不直接提供兩個方法呢?比如:DeepClone或者ShallowClone。還是,一般類型的創建,只要實現了淺拷貝就不需要再實現深拷貝(或者反之),所以我們沒有必要提供兩個方法。

下面是一個既實現了淺拷貝也實現深拷貝的例子:

技術分享代碼 [Serializable]
class Employee : ICloneable
{
publicstring IDCode { get; set; }
publicint Age { get; set; }
public Department Department { get; set; }

#region ICloneable 成員

publicobject Clone()
{
returnthis.MemberwiseClone();
}

#endregion

public Employee DeepClone()
{
using (Stream objectStream =new MemoryStream())
{
IFormatter formatter
=new BinaryFormatter();
formatter.Serialize(objectStream,
this);
objectStream.Seek(
0, SeekOrigin.Begin);
return formatter.Deserialize(objectStream) as Employee;
}
}

public Employee ShallowClone()
{
return Clone() as Employee;
}
}

實際上,ICloneable還帶來一個問題(該問題Bill Wagner在Effcitive c#中曾經論述過),那就是:如果類型繼承自ICloneable,但是同時它不是一個Sealed類型的話,它們的子類的默認Clone方法會帶來BUG(子類的Clone方法會返回父類的副本,而不是子類本身)。這會逼迫所有的子類都重寫Clone方法;

ICloneable的Clone方法的另一個問題是:它不是類型安全的,它返回的是Object,使用它的時候還設計到轉型的問題,而我們自己實現的Clone方法卻可以規避掉這個問題(如上文代碼)。

綜上所述,類型確實沒必要繼承ICloneable接口,如果類型本身需要實現拷貝功能,直接公開方法就行。如果在應用中你覺得確實必須實現這個接口的,來指正我吧。

技術分享微信掃一掃,關註最課程(www.zuikc.com),獲取更多我的文章,獲取軟件開發每日一練

改善C#程序的建議1:非用ICloneable不可的理由