• 对象的深拷贝-序列化拷贝


    简介:

    System.Object 几乎是所有的类、结构、委托类型的基类。System.Object有一个MemberwiseClone 的方法来帮助我们创建一个当前对象的实例。

    存在的问题:

    System.Object 提供的MemberwiseClone 方法只是对象的浅拷贝,只能把当前对象的非静态字段拷贝到新对象。如果属性是值类型,那么就把值拷贝一份,如果是引用类型,那么只拷贝对原对象的引用。这就意味着MemberwiseClone 不能够创建对象的深拷贝。

    解决方案:

    有很多实现深拷贝的方式,在这里我只介绍其中的2种。

    1.通过序列化和反序列化实现深拷贝。

    2.通过反射来实现深拷贝。

    今天我就先介绍第一种:序列化和反序列化实现深拷贝。

    ICloneable 接口提供给我们一个可以自定义实现拷贝的Clone方法。

    序列化就是把对象转换成字节流的过程,反序列化相反,就是把字节流转换成原对象的过程。在.NET中有很多序列化的方式,比如二进制序列化、XML序列化等等。二进制序列化要比XML序列化快得多。所以二进制序列化是比较好的序列化和反序列化。

    通过序列化和反序列化,能够实现对一个对象的深拷贝,但是前提是需要序列化和反序列化的类都要标记为serializable特性。

    下面的例子,我创建一个职员类,拥有一个部门属性。

    1 [Serializable]
    2 public class Department
    3 {
    4     public int DepartmentId { get; set; }
    5     public string DepartmentName { get; set; }
    6 }
     1 [Serializable]
     2 public class Employee : ICloneable
     3 {
     4     public int EmployeeId { get; set; }
     5     public string EmployeeName { get; set; }
     6     public Department Department { get; set; }
     7  
     8     public object Clone()
     9     {
    10         using (MemoryStream stream = new MemoryStream())
    11         {
    12             if (this.GetType().IsSerializable)
    13             {
    14                 BinaryFormatter formatter = new BinaryFormatter();
    15                 formatter.Serialize(stream, this);
    16                 stream.Position = 0;
    17                 return formatter.Deserialize(stream);
    18             }
    19             return null;
    20         }
    21     }
    22 }

    看到我们用二进制序列化和反序列化实现了IClone接口的Clone方法。这个Clone方法我们可以提出来作为一个扩展方法:

     1 public static class ObjectExtension
     2 {
     3     public static T CopyObject<T>(this object objSource)
     4     {
     5         using (MemoryStream stream = new MemoryStream())
     6         {
     7             BinaryFormatter formatter = new BinaryFormatter();
     8             formatter.Serialize(stream, objSource);
     9             stream.Position = 0;
    10             return (T)formatter.Deserialize(stream);
    11         }
    12     }
    13 }

    看源代码:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.IO;
     6 using System.Runtime.Serialization.Formatters.Binary;
     7 
     8 namespace SerializeCopy
     9 {
    10     [Serializable]
    11     public class Department
    12     {
    13         public int DepartmentId { get; set; }
    14 
    15         public string DepartmentName { get; set; }
    16     }
    17 
    18     [Serializable]
    19     public class Employee : ICloneable
    20     {
    21         public int EmployeeId { get; set; }
    22         public string EmployeeName { get; set; }
    23         public Department Department { get; set; }
    24 
    25         public Object Clone()
    26         {
    27 
    28             return ObjectExtension.CopyObject<Employee>(this);
    29         }
    30 
    31     }
    32  public static class ObjectExtension
    33     {
    34 
    35         public static T CopyObject<T>(this object objsource)
    36         {
    37             using (MemoryStream stream = new MemoryStream())
    38             {
    39                 BinaryFormatter formatter = new BinaryFormatter();
    40 
    41                 formatter.Serialize(stream, objsource);
    42                 stream.Position = 0;
    43 
    44                 return (T)formatter.Deserialize(stream);
    45 
    46             }
    47 
    48         }
    49 
    50     }
    51 
    52 }

    调用代码:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 
     6 namespace SerializeCopy
     7 {
     8     class Program
     9     {
    10         static void Main(string[] args)
    11         {
    12             Employee emp = new Employee();
    13 
    14             emp.EmployeeId = 1000;
    15             emp.EmployeeName = "IT少年";
    16             emp.Department = new Department { DepartmentId = 1, DepartmentName = "Examination" };
    17 
    18             Employee empclone = emp.Clone() as Employee;
    19 
    20             emp.EmployeeId = 1003;
    21             emp.EmployeeName = "TTT";
    22             emp.Department.DepartmentId = 3;
    23             emp.Department.DepartmentName = "admin";
    24    Console.WriteLine("----emp原始对象------");
    25             Console.WriteLine("拷贝前DepartmentName应该是admin:  " + emp.Department.DepartmentName);
    26             Console.WriteLine("拷贝前DepartmentID应该是3:  " + emp.Department.DepartmentId);
    27 
    28             Console.WriteLine("----empclone拷贝对象------");
    29             Console.WriteLine("拷贝DepartmentName应该是Examination:    " + empclone.Department.DepartmentName);
    30             Console.WriteLine("拷贝DepartmentID应该是1:     " + empclone.Department.DepartmentId);
    31             Console.ReadKey();
    32         }
    33     }
    34 }

    调用结果:

    需要注意的一点是,用序列化和反序列化深拷贝,需要将需要拷贝的属性标记为Serializable

  • 相关阅读:
    整理一些将窗口显示在前台办法
    工具
    [Windows Api 学习] Error Handling Functions
    Windows实用快捷键
    程序化交易资料汇总
    compile libpng
    zlib 1.2.8 编译笔记
    Cryptopp Usage Note
    linux环境中Java服务通过shell脚本重启(升级)自己
    搭建自己的maven库---nexus
  • 原文地址:https://www.cnblogs.com/yplong/p/5288592.html
Copyright © 2020-2023  润新知