C# 深拷贝和浅拷贝

文章目录

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;
}
相关推荐
慧都小妮子1 分钟前
Spire.PDF for .NET【页面设置】演示:打开 PDF 时自动显示书签或缩略图
java·pdf·.net
m51275 分钟前
LinuxC语言
java·服务器·前端
IU宝10 分钟前
C/C++内存管理
java·c语言·c++
湫ccc10 分钟前
《Python基础》之pip换国内镜像源
开发语言·python·pip
瓜牛_gn10 分钟前
依赖注入注解
java·后端·spring
fhvyxyci11 分钟前
【C++之STL】摸清 string 的模拟实现(下)
开发语言·c++·string
hakesashou11 分钟前
Python中常用的函数介绍
java·网络·python
qq_4597300313 分钟前
C 语言面向对象
c语言·开发语言
佚先森21 分钟前
2024ARM网络验证 支持一键云注入引流弹窗注册机 一键脱壳APP加固搭建程序源码及教程
java·html
菜鸟学Python22 分钟前
Python 数据分析核心库大全!
开发语言·python·数据挖掘·数据分析