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;
}
相关推荐
golang学习记1 分钟前
IDEA 2026.3 远程开发迎来重磅升级
java·ide·intellij-idea·远程开发
天天被压力21 分钟前
【A股分钟级高频数据完全手册 #04】指数分钟级行情数据接口:沪深指数Pro版最新分时取数
java·人工智能·python
敲代码的小小酥24 分钟前
谈SpringMVC与Spring WebFlux的区别与适用场景
java·后端·spring
天天被压力31 分钟前
【A股分钟级高频数据完全手册 #03】股票历史1分钟K线数据接口怎么用:Pro版批量拉取与本地缓存
java·人工智能·python
zhanghaha131433 分钟前
C# 系列教程_7 判断语句(分支)保姆级精讲
开发语言·c#
apcipot_rain38 分钟前
C++转Java日记(02)
java·开发语言·c++
nice_lcj5201 小时前
【从零理解 Spring AI · 03】Spring AI 在 Spring 生态里的位置
java·spring boot·大模型·spring ai·ai应用开发
杜 硕1 小时前
从零开始的C++生活——第七讲——02
开发语言·c++·生活
zhanghaha13141 小时前
C# 系列教程_8 循环语句 保姆级精讲(面向新手)
开发语言·c#
麦麦麦当劳大王9 小时前
【油猴脚本】Boss直聘 岗位职责复制
开发语言·前端·javascript