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;
}
相关推荐
嘵奇几秒前
最新版IDEA下载安装教程
java·intellij-idea
终极定律6 分钟前
qt:输入控件操作
开发语言·qt
JenKinJia22 分钟前
Windows10配置C++版本的Kafka,并进行发布和订阅测试
开发语言·c++
煤炭里de黑猫24 分钟前
Lua C API :lua_insert 函数详解
开发语言·lua
笨鸟笃行26 分钟前
爬虫第七篇数据爬取及解析
开发语言·爬虫·python
s_fox_26 分钟前
Nginx Embedded Variables 嵌入式变量解析(4)
java·网络·nginx
编程乐趣27 分钟前
一文掌握DeepSeek本地部署+Page Assist浏览器插件+C#接口调用+局域网访问!全攻略来了!
开发语言·c#
java1234_小锋32 分钟前
一周学会Flask3 Python Web开发-response响应格式
开发语言·python·flask·flask3
Jelena1577958579232 分钟前
使用Java爬虫获取1688 item_get_company 接口的公司档案信息
java·开发语言·爬虫
java1234_小锋34 分钟前
一周学会Flask3 Python Web开发-flask3模块化blueprint配置
开发语言·python·flask·flask3