[No0000178]改善C#程序的建议1:非用ICloneable不可的理由
好吧,我承認(rèn),這是一個反標(biāo)題,實(shí)際的情況是:我找不到一個非用ICloneable不可的理由。事實(shí)上,接口ICloneable還會帶來誤解,因為它只有一個Clone方法。
我們都知道,對象的拷貝分為:淺拷貝和深拷貝。ICloneable僅有一個Clone方法使我們無法從命名的角度去區(qū)分到底是哪個拷貝。
淺拷貝:將對象的字段復(fù)制到副本(新的對象)中,同時將字段的值也賦值過去,但是引用類型字段只復(fù)制引用,而不是引用類型本身。這意味著,源對象引用類型字段的值改變了,會影響到副本中對應(yīng)的值也改變;
深拷貝:將對象的字段復(fù)制到副本(新的對象)中,無論是值類型還是引用類型字段,都會復(fù)制類型本身及類型的值。這意味著,源對象引用類型字段的值改變了,不會影響到副本中對應(yīng)的值;
于是問題來了,如果類型繼承了ICloneable接口,那么類型中的Clone是淺拷貝還是深拷貝。微軟的解釋是:你既可以在Clone方法中實(shí)現(xiàn)淺拷貝,也可以實(shí)現(xiàn)深拷貝。那么,為什么不直接提供兩個方法呢?比如:DeepClone或者ShallowClone。還是,一般類型的創(chuàng)建,只要實(shí)現(xiàn)了淺拷貝就不需要再實(shí)現(xiàn)深拷貝(或者反之),所以我們沒有必要提供兩個方法。
下面是一個既實(shí)現(xiàn)了淺拷貝也實(shí)現(xiàn)深拷貝的例子:
代碼 [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;
}
}
實(shí)際上,ICloneable還帶來一個問題(該問題Bill Wagner在Effcitive c#中曾經(jīng)論述過),那就是:如果類型繼承自ICloneable,但是同時它不是一個Sealed類型的話,它們的子類的默認(rèn)Clone方法會帶來BUG(子類的Clone方法會返回父類的副本,而不是子類本身)。這會逼迫所有的子類都重寫Clone方法;
ICloneable的Clone方法的另一個問題是:它不是類型安全的,它返回的是Object,使用它的時候還設(shè)計到轉(zhuǎn)型的問題,而我們自己實(shí)現(xiàn)的Clone方法卻可以規(guī)避掉這個問題(如上文代碼)。
綜上所述,類型確實(shí)沒必要繼承ICloneable接口,如果類型本身需要實(shí)現(xiàn)拷貝功能,直接公開方法就行。如果在應(yīng)用中你覺得確實(shí)必須實(shí)現(xiàn)這個接口的,來指正我吧。
轉(zhuǎn)載于:https://www.cnblogs.com/Chary/p/No0000178.html
總結(jié)
以上是生活随笔為你收集整理的[No0000178]改善C#程序的建议1:非用ICloneable不可的理由的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 为什么总是梦到以前的女朋友
- 下一篇: 梦到浇水预示着什么