为什么要用到深拷贝呢?比如我们建了某个类Person,并且实例化出一个对象,然后,突然需要把这个对象复制一遍,并且复制出来的对象要跟之前的一模一样,来看下我们一般会怎么做,看代码

  

public class Person
{
  public string Name { get; set; }
}

class Program
{
  static void Main(string[] args)
    {
      Person sourceP = new Person() { Name = "大哥" };
      Person copyP = sourceP;
      copyP.Name = "大哥大"; // 拷贝对象改变Name值
      // 结果都是"大哥",因为实现的是浅拷贝,一个对象的改变都会影响到另一个对象
      Console.WriteLine("Person.Name: [SourceP: {0}] [CopyP:{1}]", sourceP.Name, copyP.Name);
      Console.Read();
    }
}

运行结果如图

可以看到虽然复制了一份sourceP对象,但是修改新对象copyP的Name属性时,居然把原来的sourceP对象的值也改了。这里的原理是因为“=”号,在对引用类型使用时,仅仅是新建一个新的引用变量,然后把引用地址复制给了新的引用变量而已,并没有复制真正的内容,这时候如果需要复制真正内容的话,就需要用到深拷贝的方式了。

几种常见的深拷贝方式

1、利用反射实现

public static T DeepCopyByReflection<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.Static|BindingFlags.Instance);
  foreach(var field in fields)
  {
    try
    {
      field.SetValue(retval, DeepCopyByReflection(field.GetValue(obj)));
    }
    catch { }
  }

  return (T)retval;
}

2、利用二进制序列化和反序列化

public static T DeepCopyByBinary<T>(T obj)
{
  object retval;
  using (MemoryStream ms = new MemoryStream())
  {
    BinaryFormatter bf = new BinaryFormatter();
    bf.Serialize(ms, obj);
    ms.Seek(0, SeekOrigin.Begin);
    retval = bf.Deserialize(ms);
    ms.Close();
  }
  return (T)retval;
}

注意,使用二进制序列化和反序列化时,在需要序列化的类上要加上[Serializable]

[Serializable]
public class Person
{
  public string Name { get; set; }
}

3、利用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;
}

c#实现深拷贝的几种方法的更多相关文章

  1. JS实现深拷贝的几种方法

    引 如何区分深拷贝与浅拷贝,简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝,自食其力. 此篇文章中也会简单阐述到栈 ...

  2. 【JS】深拷贝与浅拷贝的区别,实现深拷贝的几种方法

    1 借用JSON对象的parse和stringify function deepClone(obj){ let _obj = JSON.stringify(obj), objClone = JSON. ...

  3. 一步步分析Java深拷贝的两种方式-clone和序列化

    今天遇到一道面试题,询问深拷贝的两种方法.主要就是clone方法和序列化方法.今天就来分析一下这两种方式如何实现深拷贝.如果想跳过解析的朋友,直奔"重点来了!"寻找答案. clon ...

  4. JS 中深拷贝的几种实现方法

    JS 中深拷贝的几种实现方法1.使用递归的方式实现深拷贝 //使用递归的方式实现数组.对象的深拷贝 function deepClone1(obj) { //判断拷贝的要进行深拷贝的是数组还是对象,是 ...

  5. 2种方法实现java对象的深拷贝

    2种方法实现java对象的深拷贝 2017年12月03日 22:23:07 iCoding91 阅读数 4420更多 分类专栏: java   版权声明:本文为博主原创文章,遵循CC 4.0 BY-S ...

  6. js对象的深拷贝及其的几种方法

    深拷贝和浅拷贝是javascript中一个比较复杂的问题,也是面试官最喜欢问的问题之一,通过这个为可以看出是否入门,深拷贝和浅拷贝也是初学者经常犯错一个点. 简单来说深拷贝是拷贝储存在栈中的对象,而浅 ...

  7. 用浅/深拷贝、和HTML5方法解决js对象的引用的问题

    先来看一个例子 例一: var a=[1,2,3]; var b=a; b.push(4); alert(b);//1,2,3,4 alert(a);//1,2,3,4 var a=[1,2,3]; ...

  8. JS 深拷贝和浅拷贝概念,以及实现深拷贝的三种方式

    一.理解堆栈,基本数据类型与引用数据类型 1.堆栈 栈(stack):系统自动分配的内存空间,内存会由系统自动释放,用来存放函数的参数值,局部变量的值等,特点是先进后出. 堆(heap):系统动态分配 ...

  9. JS 判断数据类型的三种方法

    说到数据类型,我们先理一下JavaScript中常见的几种数据类型: 基本类型:string,number,boolean 特殊类型:undefined,null 引用类型:Object,Functi ...

随机推荐

  1. Burp Suite 基础知识(一)

    前言 大家好,我是小白,下面开始我的表演,以下内容如有雷同纯属巧合,靴靴.  (鞠躬 学到什么就写什么,可能有点乱哈. Burp Suite 是一款用于攻击 web 应用程序的集成平台,包含了许多工具 ...

  2. leadcode的Hot100系列--78. 子集--回溯

    上一篇说了使用位运算来进行子集输出,这里使用回溯的方法来进行排序. 回溯的思想,我的理解就是: 把解的所有情况转换为树或者图,然后用深度优先的原则来对所有的情况进行遍历解析. 当然,因为问题中会包涵这 ...

  3. Python:字典的高级知识

    一.字典 是另一种可变容器模型,且可存储任意类型对象.字典的每个键值(key=>value)对用冒号(:)分割,每个对之间用逗号(,)分割,整个字典包括在花括号({})中. 二.一些字典高级知识 ...

  4. Python爬虫入门:爬取pixiv

    终于想开始爬自己想爬的网站了.于是就试着爬P站试试手. 我爬的图的目标网址是: http://www.pixiv.net/search.php?word=%E5%9B%9B%E6%9C%88%E3%8 ...

  5. DStream转为DF的两种方式(突破map时元组22的限制)

    在进行Spark Streaming的开发时,我们常常需要将DStream转为DataFrame来进行进一步的处理, 共有两种方式,方式一: val spark = SparkSession.buil ...

  6. 微信小程序全局变量改变监听

    问题来源 最近工作需要写小程序页面,其中有个页面情况为:父页面中包含了一个组件页面,组件页面中又包含了另外一个组件页面.需求为:点击最后一个组件页面中的一个view,需要显示最外层父页面中的一个弹出层 ...

  7. C程序疑问解答 ——可怕的野指针

    本篇为原创,禁止任何形式的他用! 一.疑问点         指针是C语言一个很强大的功能,同时也是很容易让人犯错的一个功能,用错了指针,轻者只是报个错,重者可能整个系统都崩溃了.下面是大家在编写C程 ...

  8. [01] HEVD 双机调试环境搭建

    [01] HEVD 双机调试环境搭建 span::selection, .CodeMirror-line > span > span::selection { background: #d ...

  9. Spring Boot 2.x (十八):邮件服务一文打尽

    前景介绍 在日常的工作中,我们经常会用到邮件服务,比如发送验证码,找回密码确认,注册时邮件验证等,所以今天在这里进行邮件服务的一些操作. 大致思路 我们要做的其实就是把Java程序作为一个客户端,然后 ...

  10. 每日一问:View.getContext() 的返回一定是 Activity 么?

    坚持原创日更,短平快的 Android 进阶系列,敬请直接在微信公众号搜索:nanchen,直接关注并设为星标,精彩不容错过. 一般我们被问到这样的问题,通常来说,答案都是否定的,但一定得知道其中的原 ...