构建可克隆对象(ICloneable)
《C# 与.NET 4 高级程序设计》笔记
一个引用变量分配给另一个引用变量,那么两个引用将指向内存中的同一个对象。通过任何一个引用都能修改堆上的同样对象。
// A class named Point. public class Point //: ICloneable { public int X { get; set; } public int Y { get; set; } public Point(int xPos, int yPos) { X = xPos; Y = yPos; } public Point() { } // Override Object.ToString(). public override string ToString() { return string.Format("X = {0}; Y = {1};", X, Y); } }
static void Main(string[] args) { Console.WriteLine("***** Fun with Object Cloning *****\n"); //指向同一个对象的两个引用 Point p1 = new Point(50, 50); Point p2 = p1; p2.X = 0; Console.WriteLine(p1); Console.WriteLine(p2); Console.ReadLine(); }
结果:
实现标准ICloneable接口,可以使自定义类型具有返回自身副本的能力。
public interface ICloneable { object Clone(); }
当Point类中没有引用型数据成员时,可以直接MemberwiseClone()方法返回自身。
注意:MemberwiseClone()是System.Object的成员,这个方法是受保护的,对象用户不能直接调用这个方法,这个方法获取当前对象的一个“浅复制”。
// A class named Point. public class Point : ICloneable { public int X { get; set; } public int Y { get; set; } //public PointDescription desc = new PointDescription(); public Point(int xPos, int yPos) { X = xPos; Y = yPos; } public Point() { } // Override Object.ToString(). public override string ToString() { return string.Format("X = {0}; Y = {1};", X, Y); } // Return a copy of the current object. public object Clone() { return this.MemberwiseClone(); } }
static void Main(string[] args) { Console.WriteLine("***** Fun with Object Cloning *****\n"); Point p3 = new Point(100, 100); Point p4 = (Point)p3.Clone(); p4.X = 0; Console.WriteLine("\nChanged p4.desc.petName and p4.X"); Console.WriteLine("After modification:"); Console.WriteLine("p3: {0}", p3); Console.WriteLine("p4: {0}", p4); Console.ReadLine(); }
当Point类中包含引用型数据成员时,我们就必须对Clone()方法做进一步修改。
// A class named Point. public class Point : ICloneable { public int X { get; set; } public int Y { get; set; } public PointDescription desc = new PointDescription(); public Point(int xPos, int yPos, string petName) { X = xPos; Y = yPos; desc.PetName = petName; } public Point(int xPos, int yPos) { X = xPos; Y = yPos; } public Point() { } // Override Object.ToString(). public override string ToString() { return string.Format("X = {0}; Y = {1}; Name = {2};\nID = {3}\n", X, Y, desc.PetName, desc.PointID); } // Return a copy of the current object. // Now we need to adjust for the PointDescription member. public object Clone() { // First get a shallow copy. Point newPoint = (Point)this.MemberwiseClone(); // Then fill in the gaps. PointDescription currentDesc = new PointDescription(); currentDesc.PetName = this.desc.PetName; newPoint.desc = currentDesc; return newPoint; } } // This class describes a point. public class PointDescription { public string PetName { get; set; } public Guid PointID { get; set; } public PointDescription() { PetName = "No-name"; PointID = Guid.NewGuid(); } }
static void Main(string[] args) { Console.WriteLine("***** Fun with Object Cloning *****\n"); Console.WriteLine("Cloned p3 and stored new Point in p4"); Point p3 = new Point(100, 100, "Jane"); Point p4 = (Point)p3.Clone(); Console.WriteLine("Before modification:"); Console.WriteLine("p3: {0}", p3); Console.WriteLine("p4: {0}", p4); p4.desc.PetName = "My new Point"; p4.X = 9; Console.WriteLine("\nChanged p4.desc.petName and p4.X"); Console.WriteLine("After modification:"); Console.WriteLine("p3: {0}", p3); Console.WriteLine("p4: {0}", p4); Console.ReadLine(); }