为什么要用到深拷贝呢?比如我们建了某个类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. vue-cli初始化项目

    vue init webpack cnpm install npm run dev   初始化项目 我们用vue init命令来初始化项目,具体看一下这条命令的使用方法. vue init <t ...

  2. CentOS 6.x 安装 JDK1.8

    安装方式:rpm(此方式不需要手动配置环境变量) 1. 查看系统是否自带了jdk 查看centos是否自带了openjdk,如果有则卸载掉(当然也可以不卸载,但要注意冲突及版本的使用) # 查看 rp ...

  3. 该如何真正进入SEO行业?

    今天一个多年的朋友突然问我这个问题,他作为一个seo局外人,感觉SEO挺神秘,我认为要入行就要先了解一个SEO是什么职业,它的工作有那些,然后再考虑怎样进行学习或培训. 一.查看网站状态 seo人员每 ...

  4. JAVA String类型的一些小操作

    String类型是否包含某个String类型的函数:源字符串.contains(包含字符串)  返回值为:boolean类型(true或false) String类型把某个字符替换成另一个字符:源字符 ...

  5. POJ 3183:Stump Removal(模拟)

    http://poj.org/problem?id=3183 题意:有n个树桩,分别有一个高度h[i],要用Bomb把树桩都炸掉,如果炸的位置的两边树桩高度小于Bomb炸的树桩高度,那么小于树桩高度的 ...

  6. 使用开源框架Sqlsugar结合mysql开发一个小demo

    一.Sqlsugar简介 1.性能上有很大优势 sqlsugar是性能最好的ORM之一,具有超越Dapper的性能 ,走的是EMIT够构中间语言动态编译到程序集,完成高性能的实体绑定,达到原生水平. ...

  7. 为什么Python 3.6以后字典有序并且效率更高?

    在Python 3.5(含)以前,字典是不能保证顺序的,键值对A先插入字典,键值对B后插入字典,但是当你打印字典的Keys列表时,你会发现B可能在A的前面. 但是从Python 3.6开始,字典是变成 ...

  8. Netty-新连接接入源码解读

    本片博文来看Netty的服务端是如何处理新连接接入问题的 什么是新连接接入?以及新连接接入前,Netty处于什么状态 netty的服务端NioServerSocketChannel初始化,注册在Bos ...

  9. 关于下载安装Photoshop CS6遇到的一些问题

    关于安装Photoshop CS6顺带安装AdobeBridge CS6和Aobe Extension Manager CS6的问题 Bridge是PS的一款插件,它能兼容大多数AODBE公司的软件, ...

  10. C#中对EXCEL保存的SAVEAS方法说明

    这两天做的导出报表的项目中,因为出现了一些问题所以对于excel一些方法参数有了一些认识, 首先:开始生成的是.xls格式的excel文件,但是某个sheet发现我本来dataTable的数据有8万多 ...