对象的克隆:就是对象实例化的拷贝,在实际应用中我们其实就用到了对象拷贝,例如值类型的赋值操作,引用类型的相互赋值,值类型的装箱操作等,其实这些都属于对象的克隆操作。不是所有的对象实例都可以被克隆,它必须实现一个接口:ICloneable接口。该接口的定义:
public interface ICloneable
{
object Clone();
}
对象的克隆可以分两种:深拷贝、浅拷贝。
浅拷贝:拷贝时值类型拷贝到新的实例,对于引用类型则只拷贝引用。
深拷贝:拷贝对象和源对象是完全不同的两个实体,只是这两个实体的内容一致而已,也就是说不但引用改变了,而且实体也被复制了一份。
浅复制(浅拷贝)Demo
class Program { static void Main(string[] args) { Student s1 = new Student("Jone", 23); Student s2 = s1;//此处实际就是一个浅拷贝 s2.Age = 27; s1.ShowInfo(); } } class Student { public string Name; public int Age; public Student(string name,int age) { Name = name; Age = age; } public void ShowInfo() { Console.WriteLine("{0}'s age is {1}",Name,Age); Console.Read(); } }
值类型的赋值其实就是一种典型的深拷贝:
public void Main() { int i=100; int j=i; j=200; Console.WriteLine(i.ToString()); }
//执行结果:100
在.NET类库中,System.Array就实现了ICloneable接口,通过反射可以看到其实现的代码为:
Public object Clone() { return base.MebmberwiseClone(); }
Clone方法通过调用基类System.Object的受保护方法MemberwiseClone实现Array类型的浅拷贝。因为,在.NET中,一切方法都继承与System.Object 类,所以开发人员可以通过调用MemberClone方法来实现自定义类型的浅拷贝。
自定义类型实现拷贝Demo:
实现浅拷贝:
代码
class Enrollment : ICloneable
{
public List<Student> students = new List<Student>();
public void ShowEnrollmentInfo()
{
Console.WriteLine("以下是所有登记学生的名单:");
foreach (Student item in students)
{
Console.WriteLine("{0}'s age is {1}",item.Name,item.Age);
}
Console.Read();
}
#region ICloneable 成员
public object Clone()
{
return base.MemberwiseClone();//浅拷贝
}
#endregion
}
在使用的时候改变拷贝对象的时候会改变源对象的值,因为浅拷贝用的是同一对象实例:
代码
static void Main(string[] args)
{
Enrollment sourceStudentsList = new Enrollment();
sourceStudentsList.students.Add(new Student("jone", 20));
sourceStudentsList.students.Add(new Student("tom", 21));
//实现对象的克隆,执行浅拷贝还是深拷贝
// 取决于Clone方法的实现
Enrollment cloneStudentsList = sourceStudentsList.Clone() as Enrollment;
cloneStudentsList.students[0].Name = "Jonery";
Console.WriteLine(sourceStudentsList.students[0].Name);
Console.Read();
}
如果要实现深拷贝只要更改Enrollment类:
代码
class Enrollment : ICloneable
{
public List<Student> students = new List<Student>();
public void ShowEnrollmentInfo()
{
Console.WriteLine("以下是所有登记学生的名单:");
foreach (Student item in students)
{
Console.WriteLine("{0}'s age is {1}",item.Name,item.Age);
}
Console.Read();
}
public Enrollment()
{ }
public Enrollment(List<Student> studentList)
{
foreach (Student item in studentList)
{
students.Add(item);
}
}
#region ICloneable 成员
public object Clone()
{
return new Enrollment(students);//浅拷贝
}
#endregion
}