.Net 深克隆与浅克隆实践笔记
验证内容:
浅拷贝:是指将对象的所有字段复制到一个新对象。
对值类型字段只是简单的拷贝一个副本到目标对象,改变对象中值类型字段的值不会反映到原始对象中,因为拷贝的是副本。
引用型字段则是拷贝他的一个引用到目标对象.改变目标对象中引用类型字段的值它反映到原始对象中,因为拷贝的是指向堆上的一个地址。
深拷贝和浅拷贝不同的是对于引用字段的解决,深拷贝将会新对象中创建一个新对象和原始对象中对应字段相同(内容相同)字段也就说这个引用和原始对象引用不同 我们改变新对象中这个字段时候不会影响到原始对象中对应字段内容。
第一步建立一个测试对象
/// 用memory stream 序列化时必须添加该属性
/// </summary>
[Serializable]
public class Employee
{
public string Name { get; set; }
public int Age { get; set; }
public string Address { get; set; }
public Company Company { get; set; }
public Employee MemClone()
{
return this.MemberwiseClone() as Employee;
}
public Employee DeepClone()
{
using (MemoryStream memStream = new MemoryStream())
{
BinaryFormatter binaryFormatter = new BinaryFormatter(null,
new StreamingContext(StreamingContextStates.Clone));
binaryFormatter.Serialize(memStream, this);
memStream.Seek(0, SeekOrigin.Begin);
return binaryFormatter.Deserialize(memStream) as Employee;
}
}
public Employee ManualClone()
{
Employee emp = new Employee();
emp.Name = this.Name;
emp.Address = this.Address;
emp.Age = this.Age;
emp.Company = this.Company;
return emp;
}
}
[Serializable]
public class Company
{
public string CompanyName { get; set; }
public string Address { get; set; }
public int ID { get; set; }
}
第二步建立测试用例:
{
public Employee GetEmployee()
{
Employee emp = new Employee()
{
Name = "wn",
Age = 24,
Address = "XXAADDCC",
Company = new Company()
{
ID = 1090,
Address = "DFEFACE",
CompanyName = "宇宙集团总公司"
}
};
return emp;
}
public void TestMemClone()
{
Employee emp = GetEmployee();
Employee newEmp = emp.MemClone();
newEmp.Address = "dex";
//字符串类型的值并没有发生变化
Console.WriteLine("newEmp.Address:{0}", newEmp.Address);
Console.WriteLine("emp.Address:{0}", emp.Address);
newEmp.Age = 25;
//整形的值也没有发生变化
Console.WriteLine("newEmp.Age:{0}", newEmp.Age);
Console.WriteLine("emp.Age:{0}", emp.Age);
newEmp.Company.CompanyName = "EEE";
Console.WriteLine("newEmp.Company.CompanyName:{0}", newEmp.Company.CompanyName);
Console.WriteLine("emp.Company.CompanyName:{0}", emp.Company.CompanyName);
}
public void TestDeepClone()
{
Employee emp = GetEmployee();
Employee newEmp = emp.DeepClone();
newEmp.Address = "dex";
//字符串类型的值并没有发生变化
Console.WriteLine("newEmp.Address:{0}", newEmp.Address);
Console.WriteLine("emp.Address:{0}", emp.Address);
newEmp.Age = 25;
//整形的值也没有发生变化
Console.WriteLine("newEmp.Age:{0}", newEmp.Age);
Console.WriteLine("emp.Age:{0}", emp.Age);
newEmp.Company.CompanyName = "DDDDDD";
Console.WriteLine("newEmp.Company.CompanyName:{0}", newEmp.Company.CompanyName);
Console.WriteLine("emp.Company.CompanyName:{0}", emp.Company.CompanyName);
}
public void ManualClone()
{
Employee emp = GetEmployee();
Employee newEmp = emp.ManualClone();
newEmp.Address = "dex";
//字符串类型的值并没有发生变化
Console.WriteLine("newEmp.Address:{0}", newEmp.Address);
Console.WriteLine("emp.Address:{0}", emp.Address);
newEmp.Age = 25;
//整形的值也没有发生变化
Console.WriteLine("newEmp.Age:{0}", newEmp.Age);
Console.WriteLine("emp.Age:{0}", emp.Age);
newEmp.Company.CompanyName = "DDDDDD";
Console.WriteLine("newEmp.Company.CompanyName:{0}", newEmp.Company.CompanyName);
Console.WriteLine("emp.Company.CompanyName:{0}", emp.Company.CompanyName);
}
}
{
CloneTest test = new CloneTest();
test.TestMemClone();
Console.WriteLine();
Console.WriteLine();
Console.WriteLine();
test.TestDeepClone();
Console.WriteLine();
Console.WriteLine();
Console.WriteLine();
test.ManualClone();
Console.ReadLine();
}
输出为:
newEmp.Address:dex
emp.Address:XXAADDCC
newEmp.Age:25
emp.Age:24
newEmp.Company.CompanyName:EEE
emp.Company.CompanyName:EEE
newEmp.Address:dex
emp.Address:XXAADDCC
newEmp.Age:25
emp.Age:24
newEmp.Company.CompanyName:DDDDDD
emp.Company.CompanyName:宇宙集团总公司
newEmp.Address:dex
emp.Address:XXAADDCC
newEmp.Age:25
emp.Age:24
newEmp.Company.CompanyName:DDDDDD
emp.Company.CompanyName:DDDDDD
结论:
1、实现结论和验证内容吻合。
2、通过手工new对象逐个赋值和MemberwiseClone表现是一致的,所有能用MemberwiseClone的时候尽量用MemberwiseClone。
3、字符串虽然为引用类型但其表现和值类型是一致的。
4、用内存流序列化对象的方法要求该对象的中的引用类型必须添加[Serializable]声明。