執行程式發現 d2 為 null。雖 Derived 衍生自 BaseType,但繼承的 Clone() 無法正確支援 Derived:只複製基類。BaseType.Clone() 建立 BaseType 物件,非衍生 Derived 物件。這就是 d2 為 null 而非衍生物件的原因。即使克服此問題,BaseType.Clone() 也無法正確複製 Derived 中定義的 _dValues 陣列。一旦實作 ICloneable,強制所有衍生類別也必須正確實作。實際上應提供 Hook 函式,讓所有衍生類別使用你的複製實作(原則 21)。複製時,衍生類別可只對實值型別成員或實作 ICloneable 的引用型別成員複製。對衍生類別是嚴格要求。基類實作 ICloneable 通常給衍生類別添加負擔,故密封類別中應避免實作 ICloneable。
整個繼承結構必須實作 ICloneable 時,可建立抽象 Clone() 方法,強制所有衍生類別實作。
需定義方法讓衍生類別建立基類成員副本。可透過受保護建構函式實現:
class BaseType
{
private string _label;
private int[] _values;
protected BaseType() { _label = "class name"; _values = new int[10]; }
protected BaseType(BaseType right) { _label = right._label; _values = right._values.Clone() as int[]; }
}
sealed class Derived : BaseType, ICloneable
{
private double[] _dValues = new double[10];
public Derived() { _dValues = new double[10]; }
private Derived(Derived right) : base(right) { _dValues = right._dValues.Clone() as double[]; }
static void Main(string[] args)
{
Derived d = new Derived();
Derived d2 = d.Clone() as Derived;
if (d2 == null) Console.WriteLine("null");
}
public object Clone() { Derived rVal = new Derived(this); return rVal; }
}
基類不實作 ICloneable;透過受保護建構函式讓衍生類別複製基類成員。葉子類別應為密封,必要時實作 ICloneable。基類不應強迫所有衍生類別實作 ICloneable,但應提供必要方法,讓希望實作的衍生類別使用。
ICloneable 有用武之地,但相對其規則,應避免它。實值型別勿實作 ICloneable,用指派陳述式。引用型別僅在複製確實必要時,在葉子類別實作 ICloneable 支援。基類可能要支援 ICloneable 時,應建立受保護建構函式。總之,盡量避免使用 ICloneable。