C#中的对象深拷贝和浅拷贝

· 浏览次数 : 0

小编点评

**C# 中对象深拷贝和浅拷贝概述** **浅拷贝** * 只复制对象的值类型成员。 * 引用类型成员的引用则保持不变。 * 效率更高,但可能导致无法避免意外修改原始对象的异常。 **深拷贝** * 不仅复制对象的值类型成员,而且还复制所有引用类型成员的实际对象。 * 效率相对低,但可以避免无法避免意外修改原始对象的异常。 **示例代码** **浅拷贝** ```csharp public static class Person { public string Name { get; set; } public int Age { get; set; } public Address Address { get; set; } public Person Clone() { return (Person)this.MemberwiseClone(); } } ``` **深拷贝** ```csharp public static class Person { public string Name { get; set; } public int Age { get; set; } public Address Address { get; set; } public static void Copy2() { Person person1 = new Person() { Name = "张三", Address = new Address() { City = "北京" } }; // 深拷贝1 反射 Person person2 = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(person1)); // 修改原对象的属性 person1.Address.City = "上海"; person2.Name = "李四"; person2.Address.City = "昆明"; Console.WriteLine("原对象和副本不相互影响。"); } } ``` **结论** 选择使用浅拷贝还是深拷贝取决于需要的数据传输效率和避免意外修改原始对象的风险。

正文

C#中的对象深拷贝和浅拷贝

概述

在C#中,对象拷贝是指将一个对象的副本创建到另一个对象中。对象拷贝通常用于数据传输或创建对象的新实例。

C#中有两种主要的拷贝方式:浅拷贝和深拷贝

1. 浅拷贝

浅拷贝是指只拷贝对象的值类型成员,而引用类型成员的引用则保持不变。这意味着新的对象和原始对象将共享所有引用类型成员的实际对象。

实现方式

  • this.MemberwiseClone();

示例代码

实体

public class Person
{
    public Person()
    {
        this.Address = new Address();
    }
    public string Name { get; set; }
     public int Age { get; set; }
    public Address Address { get; set; }

    public Person Clone()
    {
        return (Person)this.MemberwiseClone();
    }
}

public class Address
{
    public string Street { get; set; }
    public string City { get; set; }
}

调用

 Person person1 = new Person()
 {
     Name = "张三",
     Address = new Address()
     {
         City = "北京",
     }
 };

 Person person2 = person1.Clone();//浅拷贝
 //修改原对象的属性
 person1.Address.City = "上海";
 //修改副本对象的属性
 person2.Name = "李四";
 person2.Address.City = "昆明";
 string result = $"原对象{JsonConvert.SerializeObject(person1)}。副本{JsonConvert.SerializeObject(person2)}";
 MessageBox.Show($"浅拷贝:原对象和副本修改引用类型属性后相互影响。{result}");

2. 深拷贝

深拷贝是指不仅拷贝对象的值类型成员,而且还拷贝所有引用类型成员的实际对象。这意味着新的对象将拥有其引用类型成员的完全独立副本。

实现方式

  • 反射
  • 序列化
  • 对象映射(三方开源如TinyMapper、AutoMapper)。

示例代码

/// <summary>
/// 深拷贝
/// </summary>
public static void Copy2()
{
    Person person1 = new Person()
    {
        Name = "张三",
        Address = new Address()
        {
            City = "北京",
        }
    };

    //Person person2 = CreateDeepCopy(person1);//深拷贝1反射
    // Person person2 =JsonConvert.DeserializeObject<Person>(JsonConvert.SerializeObject(person1));//深拷贝2序列化
    Person person2 =person1.MapTo<Person,Person>();//深拷贝3对象映射
    //修改原对象的属性
    person1.Address.City = "上海";
    //修改副本对象的属性
    person2.Name = "李四";
    person2.Address.City = "昆明";
    string result = $"原对象{JsonConvert.SerializeObject(person1)}。副本{JsonConvert.SerializeObject(person2)}";
    MessageBox.Show($"深拷贝:原对象和副本不相互影响。{result}");
}


/// <summary>
/// 使用反射进行深拷贝
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="original"></param>
/// <returns></returns>
static T CreateDeepCopy<T>(T original)
{
    if (original == null)
    {
        return default(T);
    }

    Type type = original.GetType();
    object newObject = Activator.CreateInstance(type);

    foreach (FieldInfo fieldInfo in type.GetFields())
    {
        if (fieldInfo.IsStatic)
        {
            continue;
        }

        object value = fieldInfo.GetValue(original);
        fieldInfo.SetValue(newObject, CreateDeepCopy(value));
    }

    return (T)newObject;
}

总结

浅拷贝通常用于数据传输,因为它是快速且有效的。但是,如果需要避免意外修改原始对象,则应使用深拷贝。

以下是一些有关何时使用浅拷贝和深拷贝的准则:

  • 使用浅拷贝:
    • 当需要快速创建对象副本时
    • 当原始对象不可变时
    • 当原始对象和副本不会同时使用时
  • 使用深拷贝:
    • 当需要避免意外修改原始对象时
    • 当原始对象和副本需要同时使用时
    • 当原始对象包含引用类型成员时

引用

与C#中的对象深拷贝和浅拷贝相似的内容:

C#中的对象深拷贝和浅拷贝

目录C#中的对象深拷贝和浅拷贝概述1. 浅拷贝2. 深拷贝总结引用 C#中的对象深拷贝和浅拷贝 概述 在C#中,对象拷贝是指将一个对象的副本创建到另一个对象中。对象拷贝通常用于数据传输或创建对象的新实例。 C#中有两种主要的拷贝方式:浅拷贝和深拷贝 1. 浅拷贝 浅拷贝是指只拷贝对象的值类型成员,而

C#中的浅拷贝与深拷贝

## 前言 众所周知,C#中有两种类型变量:那就是**值类型**和**引用类型**。对于值类型而言,copy就相当于是全盘复制了,真正的实现了复制,属于**深拷贝**;而对于引用类型而言,一般的copy只是**浅拷贝**,只是copy到了引用对象的地址,相当于值传递了一个引用指针,==新的对象通过地

使用c#强大的表达式树实现对象的深克隆

一、表达式树的基本概念 表达式树是一个以树状结构表示的表达式,其中每个节点都代表表达式的一部分。例如,一个算术表达式 a + b 可以被表示为一个树,其中根节点是加法运算符,它的两个子节点分别是 a 和 b。在 LINQ(语言集成查询)中,表达式树使得能够将 C# 中的查询转换成其他形式的查询,比如

使用c#强大的表达式树实现对象的深克隆之解决循环引用的问题

在上一期博客里,我们提到使用使用c#强大的表达式树实现对象的深克隆,文章地址:https://www.cnblogs.com/gmmy/p/18186750。但是文章里没有解决如何实现循环引用的问题。 循环引用 在C#中,循环引用通常发生在两个或更多的对象相互持有对方的引用,从而形成一个闭环。这种情

二分查找 | C++

以此题为例:P2249 【深基13.例1】查找 二分查找 对于一个单调不降的序列 \(S\),传统查找的复杂度是 \(O(|S|)\),即 \(O(n)\). 有时候序列 \(S\) 中的元素特别多,或者你希望尽量减小复杂度,那么,有没有复杂度更低的方法呢? 理论上是不行的,因为读入的复杂度已经达到

c++临时对象导致的生命周期问题

对象的生命周期是c++中非常重要的概念,它直接决定了你的程序是否正确以及是否存在安全问题。 今天要说的临时变量导致的生命周期问题是非常常见的,很多时候没有一定经验甚至没法识别出来。光是我自己写、review、回答别人的问题就犯了或者看到了许许多多这类问题,所以我想有必要做个简单的总结,自己备忘的同时

深入理解 C++ 中的多态与文件操作

C++ 多态 多态(Polymorphism)是面向对象编程(OOP)的核心概念之一,它允许对象在相同操作下表现出不同的行为。在 C++ 中,多态通常通过继承和虚函数来实现。 理解多态 想象一个场景,你有一个动物园,里面有各种动物,如猫、狗、鸟等。每个动物都有自己的叫声。使用面向对象编程,我们可以创

C++的动态分派在HotSpot VM中的重要应用

众所周知,多态是面向对象编程语言的重要特性,它允许基类的指针或引用指向派生类的对象,而在具体访问时实现方法的动态绑定。C++ 和 Java 作为当前最为流行的两种面向对象编程语言,其内部对于多态的支持对于单继承的实现非常类似。 首先来体现一下C++的动态分派,如下: class Base1{ pub

6.0 Python 使用函数装饰器

装饰器可以使函数执行前和执行后分别执行其他的附加功能,这种在代码运行期间动态增加功能的方式,称之为`"装饰器"(Decorator)`,装饰器的功能非常强大,装饰器一般接受一个函数对象作为参数,以对其进行增强,相当于C++中的构造函数,与析构函数。装饰器本质上是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象.它经常用于有迫切需求的场

深度解读《深度探索C++对象模型》之数据成员的存取效率分析(二)

C++对象在经过类的封装后,存取对象中的数据成员的效率是否相比C语言的结构体访问效率要低下?本篇将从C++类的不同定义形式来一一分析C++对象的数据成员的访问在编译器中是如何实现的,以及它们的存取效率如何?