当前位置: 首页 > 编程笔记 >

简单谈谈C#中深拷贝、浅拷贝

范瀚昂
2023-03-14
本文向大家介绍简单谈谈C#中深拷贝、浅拷贝,包括了简单谈谈C#中深拷贝、浅拷贝的使用技巧和注意事项,需要的朋友参考一下

Object.MemberwiseClone 方法

创建当前 Object 的浅表副本。

protected Object MemberwiseClone()

MemberwiseClone 方法创建一个浅表副本,方法是创建一个新对象,然后将当前对象的非静态字段复制到该新对象。 如果字段是值类型的,则对该字段执行逐位复制。 如果字段是引用类型,则复制引用但不复制引用的对象;因此,原始对象及其复本引用同一对象。

例如,考虑对象X引用对象 A 和 B , 对象 B 依次引用对象 C。 X 的浅表副本创建一个新对象 X2,该对象也引用对象 A 和 B。 相比而言,X 的深层副本创建一个新对象 X2,该对象引用新对象 A2 和 B2(分别为 A 和 B 的副本)。 B2 又引用新对象 C2,C2 是 C 的副本。 该示例阐释了浅层和深层复制操作之间的区别。

有很多方法可以实现深层复制操作,前提是浅表复制操作由 MemberwiseClone 方法执行但不符合您的需求。

这些要求包括:

调用要复制的对象的类构造函数以创建含有从第一个对象中提出的属性值的第二个对象。 这假定对象的值完全由类构造函数定义。

调用 MemberwiseClone 方法创建的对象的浅表副本,然后将指定新的对象,其值均相同,原始对象的任何属性或字段的值是引用类型。 该示例中的 DeepCopy 方法阐释了这种方法。

序列化要深层复制的对象,然后将序列化的数据还原到另一个对象变量。

使用带递归的反射执行的深层复制操作。

 下面的示例演示 MemberwiseClone 方法。 它定义了 ShallowCopy 方法,该方法通过调用 MemberwiseClone 方法来在 Person 对象上执行浅表复制操作。 它还定义了在 Person 对象上执行深层复制操作的DeepCopy 方法。

using System;
 
public class IdInfo
{
  public int IdNumber;
 
  public IdInfo(int IdNumber)
  {
    this.IdNumber = IdNumber;
  }
}
 
public class Person
{
  public int Age;
  public string Name;
  public IdInfo IdInfo;
 
  public Person ShallowCopy()
  {
    return (Person)this.MemberwiseClone();
  }
 
  public Person DeepCopy()
  {
    Person other = (Person) this.MemberwiseClone();
    other.IdInfo = new IdInfo(this.IdInfo.IdNumber);
    return other;
  }
}
 
public class Example
{
  public static void Main()
  {
    // Create an instance of Person and assign values to its fields.
    Person p1 = new Person();
    p1.Age = 42;
    p1.Name = "Sam";
    p1.IdInfo = new IdInfo(6565);
 
    // Perform a shallow copy of p1 and assign it to p2.
    Person p2 = (Person) p1.ShallowCopy();
 
    // Display values of p1, p2
    Console.WriteLine("Original values of p1 and p2:");
    Console.WriteLine("  p1 instance values: ");
    DisplayValues(p1);
    Console.WriteLine("  p2 instance values:");
    DisplayValues(p2);
 
    // Change the value of p1 properties and display the values of p1 and p2.
    p1.Age = 32;
    p1.Name = "Frank";
    p1.IdInfo.IdNumber = 7878;
    Console.WriteLine("\nValues of p1 and p2 after changes to p1:");
    Console.WriteLine("  p1 instance values: ");
    DisplayValues(p1);
    Console.WriteLine("  p2 instance values:");
    DisplayValues(p2);
 
    // Make a deep copy of p1 and assign it to p3.
    Person p3 = p1.DeepCopy();
    // Change the members of the p1 class to new values to show the deep copy.
    p1.Name = "George";
    p1.Age = 39;
    p1.IdInfo.IdNumber = 8641;
    Console.WriteLine("\nValues of p1 and p3 after changes to p1:");
    Console.WriteLine("  p1 instance values: ");
    DisplayValues(p1);
    Console.WriteLine("  p3 instance values:");
    DisplayValues(p3);
  }
 
  public static void DisplayValues(Person p)
  {
    Console.WriteLine("   Name: {0:s}, Age: {1:d}", p.Name, p.Age);
    Console.WriteLine("   Value: {0:d}", p.IdInfo.IdNumber);
  }
}
// The example displays the following output:
//    Original values of p1 and p2:
//     p1 instance values:
//       Name: Sam, Age: 42
//       Value: 6565
//     p2 instance values:
//       Name: Sam, Age: 42
//       Value: 6565
//   
//    Values of p1 and p2 after changes to p1:
//     p1 instance values:
//       Name: Frank, Age: 32
//       Value: 7878
//     p2 instance values:
//       Name: Sam, Age: 42
//       Value: 7878
//   
//    Values of p1 and p3 after changes to p1:
//     p1 instance values:
//       Name: George, Age: 39
//       Value: 8641
//     p3 instance values:
//       Name: Frank, Age: 32
//       Value: 7878

为了实现深度复制,我们就必须遍历有相互引用的对象构成的图,并需要处理其中的循环引用结构。这无疑是十分复杂的。幸好借助.Net的序列化和反序列化机制,可以十分简单的深度Clone一个对象。

原理很简单,首先将对象序列化到内存流中,此时对象和对象引用的所用对象的状态都被保存到内存中。.Net的序列化机制会自动处理循环引用的情况。然后将内存流中的状态信息反序列化到一个新的对象中。

这样一个对象的深度复制就完成了。在原型设计模式中CLONE技术非常关键。

using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
 
namespace CloneDemo
{
  [Serializable]
  class DemoClass
  {
    public int i = 0;
    public int[] iArr = { 1, 2, 3 };
 
    public DemoClass Clone1() //浅CLONE
    {
      return this.MemberwiseClone() as DemoClass;
    }
 
    public DemoClass Clone2() //深clone
    {
      MemoryStream stream = new MemoryStream();
      BinaryFormatter formatter = new BinaryFormatter();
      formatter.Serialize(stream, this);
      stream.Position = 0;
      return formatter.Deserialize(stream) as DemoClass;
    }
  }
 
  class Program
  {
    static void Main(string[] args)
    {
      DemoClass a = new DemoClass();
      a.i = 10;
      a.iArr = new int[] { 8, 9, 10 };
      DemoClass b = a.Clone1();
      DemoClass c = a.Clone2();
 
      // 更改 a 对象的iArr[0], 导致 b 对象的iArr[0] 也发生了变化 而 c不会变化
       a.iArr[0] = 88;
 
      Console.WriteLine("MemberwiseClone");
      Console.WriteLine(b.i);
      foreach (var item in b.iArr)
      {
        Console.WriteLine(item);
      }
 
      Console.WriteLine("Clone2");
      Console.WriteLine(c.i);
      foreach (var item in c.iArr)
      {
        Console.WriteLine(item);
      }
 
      Console.ReadLine();
    }
  }
}

以上所述就是本文的全部内容了,希望大家能够喜欢。

 类似资料:
  • 本文向大家介绍浅谈Python浅拷贝、深拷贝及引用机制,包括了浅谈Python浅拷贝、深拷贝及引用机制的使用技巧和注意事项,需要的朋友参考一下 这礼拜碰到一些问题,然后意识到基础知识一段时间没巩固的话,还是有遗忘的部分,还是需要温习,这里做份笔记,记录一下 前续 先简单描述下碰到的题目,要求是写出2个print的结果 可以看到,a指向了一个列表list对象,在Python中,这样的赋值语句,其实内

  • 主要内容:到底是浅拷贝还是深拷贝对于基本类型的数据以及简单的对象,它们之间的拷贝非常简单,就是按位复制内存。例如: b 和 obj2 都是以拷贝的方式初始化的,具体来说,就是将 a 和 obj1 所在内存中的数据按照二进制位(Bit)复制到 b 和 obj2 所在的内存, 这种默认的拷贝行为就是 浅拷贝 ,这和调用 memcpy() 函数的效果非常类似。 对于简单的类,默认的拷贝构造函数一般就够用了,我们也没有必要再显式地定义一

  • 浅拷贝 对于对象或数组类型,当我们将a赋值给b,然后更改b中的属性,a也会随着变化。 也就是说,a和b指向了同一块堆内存,所以修改其中任意的值,另一个值都会随之变化,这就是浅拷贝。 深拷贝 那么相应的,如果给b放到新的内存中,将a的各个属性都复制到新内存里,就是深拷贝。 也就是说,当b中的属性有变化的时候,a内的属性不会发生变化。 参考链接: 深拷贝与浅拷贝的实现(一) javaScript中浅拷

  • 本文向大家介绍浅谈C#中List 对象的深度拷贝问题,包括了浅谈C#中List 对象的深度拷贝问题的使用技巧和注意事项,需要的朋友参考一下 一、List<T>对象中的T是值类型的情况(int 类型等) 对于值类型的List直接用以下方法就可以复制: 二、List<T>对象中的T是引用类型的情况(例如自定义的实体类) 1、对于引用类型的List无法用以上方法进行复制,只会复制List中对象的引用,可

  • 一、引言 对象拷贝(Object Copy)就是将一个对象的属性拷贝到另一个有着相同类类型的对象中去。在程序中拷贝对象是很常见的,主要是为了在新的上下文环境中复用对象的部分或全部数据。Java中有三种类型的对象拷贝:浅拷贝(Shallow Copy)、深拷贝(Deep Copy)、延迟拷贝(Lazy Copy)。 二、浅拷贝 1、什么是浅拷贝 浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着

  • 本文向大家介绍浅谈C++的浅拷贝出现的错误,包括了浅谈C++的浅拷贝出现的错误的使用技巧和注意事项,需要的朋友参考一下 之前看一些资料提到浅拷贝的问题,即在复制对象时,只是对对象中的数据成员进行简单的赋值,默认拷贝构造函数执行的也是浅拷贝。如果对象中存在动态成员,如指针,那么仅仅做浅拷贝是不够的,并且容易引发错误,最经典的例子: 执行这段代码会出现崩溃,因为析构函数里的delete m_p执行了两