文章目录
- 1.深拷贝
- 2.浅拷贝
- 3.拷贝类
- 4.浅拷贝的实现
- 5.深拷贝实现
-
- [5.1 浅拷贝对象,对引用类型重新一个个赋值](#5.1 浅拷贝对象,对引用类型重新一个个赋值)
- [5.2 反射实现](#5.2 反射实现)
- [5.3 利用XML序列化和反序列化实现](#5.3 利用XML序列化和反序列化实现)
1.深拷贝
拷贝一个对象时,不仅仅把对象的引用进行复制,还把该对象引用的值也一起拷贝。这样进行深拷贝后的拷贝对象就和源对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。
csharp
int source = 123;
// 值类型赋值内部执行深拷贝
int copy = source;
// 对拷贝对象进行赋值不会改变源对象的值
copy = 234;
Console.WriteLine($"source = {source},copy = {copy}"); // 123 234
// 同样对源对象赋值也不会改变拷贝对象的值
source = 345;
Console.WriteLine($"source = {source},copy = {copy}"); // 345 234
深拷贝示意图:
2.浅拷贝
==拷贝一个对象时,仅仅拷贝对象的引用进行拷贝,但是拷贝对象和源对象还是引用同一份实体。==此时,其中一个对象的改变都会影响到另一个对象。
csharp
public class Person
{
public string Name { get; set; }
}
public static void Main(string[] args)
{
Person sourceP = new Person() { Name = "张三" };
Person copyP = sourceP; // 浅拷贝
copyP.Name = "张老三"; // 拷贝对象改变Name值,源对象Name值也会改变
Console.WriteLine("Person.Name: [SourceP: {0}] [CopyP:{1}]", sourceP.Name, copyP.Name); // 张老三 张老三
}
浅拷贝示意图:
3.拷贝类
csharp
//年级
public class Grade
{
public int Stu_Grade { get; set; }
}
//学生
public class Student
{
public string Name { get; set; }
public int Age { get; set; }
public Grade Grade { get; set; }
// 调用Object的MemberwiseClone方法实现浅拷贝
public Student ShallowCopy()
{
return (Student)this.MemberwiseClone();
}
// 输出学生信息
public override string ToString()
{
return $"姓名:{Name},年龄:{Age},年纪:{Grade.Stu_Grade}";
}
}
4.浅拷贝的实现
浅拷贝的实现是调用受保护的方法Object.MemberwiseClone()
csharp
public static void Main(string[] args)
{
Student sourceStu = new Student
{
Name = "ming",
Age = 18,
Grade = new Grade{ Stu_Grade = 6 }
};
Student copyStu = sourceStu.ShallowCopy();
// 输出修改信息前,源学生和拷贝学生信息
Console.WriteLine("------修改前------");
Console.WriteLine("源学生信息" + sourceStu.ToString());
Console.WriteLine("拷贝信息" + copyStu.ToString());
copyStu.Name = "Tom";
copyStu.Age = 26;
copyStu.Grade.Stu_Grade = 10;
// 输出修改信息后,源学生和拷贝学生信息
Console.WriteLine("------修改后------");
Console.WriteLine("源学生信息" + sourceStu.ToString());
Console.WriteLine("拷贝信息" + copyStu.ToString());
}
输出:
------修改前------
源学生信息姓名:ming,年龄:18,年级:6
拷贝信息姓名:ming,年龄:18,年级:6
------修改后------
源学生信息姓名:ming,年龄:18,年级:10
拷贝信息姓名:Tom,年龄:26,年级:10
5.深拷贝实现
5.1 浅拷贝对象,对引用类型重新一个个赋值
csharp
public Student DeepCopy()
{
Student student = (Student)this.MemberwiseClone();
student.Grade = new Grade{ Stu_Grade = student.Grade.Stu_Grade };
return student;
}
采用和浅拷贝一样的测试数据进行测试,输出:
------修改前------
源学生信息姓名:ming,年龄:18,年级:6
拷贝信息姓名:ming,年龄:18,年级:6
------修改后------
源学生信息姓名:ming,年龄:18,年级:6
拷贝信息姓名:Tom,年龄:26,年级:10
5.2 反射实现
拷贝对象:
csharp
//年级
public class Grade
{
public int Stu_Grade { get; set; }
}
// 成绩
public class Score
{
public Science Science { get; set; }
public Arts Arts { get; set; }
}
// 理科
public class Science
{
// 数学
public int Math { get; set; }
}
// 文科
public class Arts
{
// 语文
public int Chinese { get; set; }
}
//学生
public class Student
{
public string Name { get; set; }
public int Age { get; set; }
public Grade Grade { get; set; }
public Score Scroe { get; set; }
}
深拷贝实现:
csharp
public class DeepCopyHelper
{
// 反射实现深拷贝
public static T DeepCopyByReflect<T>(T obj)
{
//如果是字符串或值类型则直接返回
if (obj is string || obj.GetType().IsValueType) return obj;
object retval = Activator.CreateInstance(obj.GetType());
FieldInfo[] fields = obj.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
foreach (FieldInfo field in fields)
{
// 解决层次引用类型
try { field.SetValue(retval, DeepCopyByReflect(field.GetValue(obj))); }
catch { }
}
return (T)retval;
}
}
测试:
csharp
public static void Main(string[] args)
{
Student sourceStu = new Student
{
Name = "ming",
Age = 18,
Grade = new Grade{ Stu_Grade = 6 },
Scroe = new Score{ Arts = new Arts{Chinese = 90}, Science = new Science{Math = 90}}
};
Student copyStu = DeepCopyHelper.DeepCopyByReflect<Student>(sourceStu);
// 输出修改信息前,源学生和拷贝学生信息
Console.WriteLine("------修改前------");
Console.WriteLine("源学生信息" + sourceStu.ToString());
Console.WriteLine("拷贝信息" + copyStu.ToString());
copyStu.Name = "Tom";
copyStu.Age = 26;
copyStu.Grade.Stu_Grade = 10;
copyStu.Scroe.Arts.Chinese = 100;
copyStu.Scroe.Science.Math = 100;
// 输出修改信息后,源学生和拷贝学生信息
Console.WriteLine("------修改后------");
Console.WriteLine("源学生信息" + sourceStu.ToString());
Console.WriteLine("拷贝信息" + copyStu.ToString());
}
结果:
------修改前------
源学生信息姓名:ming,年龄:18,年级:6, 成绩:(语文:90,数学:90)
拷贝信息姓名:ming,年龄:18,年级:6, 成绩:(语文:90,数学:90)
------修改后------
源学生信息姓名:ming,年龄:18,年级:6, 成绩:(语文:90,数学:90)
拷贝信息姓名:Tom,年龄:26,年级:10, 成绩:(语文:100,数学:100)
5.3 利用XML序列化和反序列化实现
测试内容和结果和5.2一样
csharp
// xml 实现深拷贝
public static T DeepCopyByXml<T>(T obj)
{
object retval;
using (MemoryStream ms = new MemoryStream())
{
XmlSerializer xml = new XmlSerializer(typeof(T));
xml.Serialize(ms, obj);
ms.Seek(0, SeekOrigin.Begin);
retval = xml.Deserialize(ms);
ms.Close();
}
return (T)retval;
}