详解 c# 克隆

 更新时间:2020-11-21 21:08:21   作者:佚名   我要评论(0)

克隆方法是原型设计模式中必须使用的方式,它将返回一个与当前对象数据一致的对象。正如其名,犹如一个模子雕刻而出。克隆类型分为两种:浅克隆、深克隆。
1、浅克隆

克隆方法是原型设计模式中必须使用的方式,它将返回一个与当前对象数据一致的对象。正如其名,犹如一个模子雕刻而出。克隆类型分为两种:浅克隆、深克隆。

1、浅克隆

浅克隆方式是最简单、最直接的方式。只需要类实现接口ICloneable(在命名空间System.Runtime.InteropServices下)的Clone方法,在方法中使用加入对当前类的MemberwiseClone()方法即可。在浅克隆中,如果原型对象的成员变量是值类型,将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象。

如:

public class Student:ICloneable
{
  /// <summary>
  /// 值类型
  /// </summary>
  public int ID { get; set; }   /// <summary>
  /// 引用类型
  /// </summary>
  public object obj { get; set; }

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

以上方法实现了对类对象的浅克隆方式。但是在该类中具有引用类型字段,浅克隆方法无法对引用字段进行克隆,引用字段仅仅是对其进行了地址引用。所以,当修改原本或者副本的引用字段的数据时,另一个对象的引用对象的数据同样会变化。深克隆将有效的解决此问题。

2、深克隆

深克隆相对于浅克隆方式比较复杂。深克隆是无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象,深克隆将原型对象的所有引用对象也复制一份给克隆对象。

深克隆实现的机制是将对象进行序列化为数据后,再次将数据反序列化为新的对象。序列化就是将对象写到流的过程,写到流中的对象是原有对象的一个拷贝,而原对象仍然存在于内存中。通过序列化实现的拷贝不仅可以复制对象本身,而且可以复制其引用的成员对象,因此通过序列化将对象写到一个流中,再从流里将其读出来,可以实现深克隆。注意,在实现序列化前需要在类的上方标记为可序列化。本文采用的序列化方式为二进制序列化。

主要实现的代码如下:

[Serializable]//标记特性:可序列化
 public class Student
 {
   /// <summary>
   /// 值类型
   /// </summary>
   public int ID { get; set; }
   /// <summary>
   /// 引用类型
   /// </summary>
   public object obj { get; set; }

   public Student Clone( )
   {
     Student clone = new Student();
     using (Stream stream = new MemoryStream())
     {
       IFormatter formatter = new BinaryFormatter();
       try
       {
         formatter.Serialize(stream, this);
         stream.Seek(0, SeekOrigin.Begin);
         clone = formatter.Deserialize(stream) as Student;
       }
       catch (SerializationException e)
       {
         Console.WriteLine("Failed to serialize. Reason: " + e.Message);
         throw;
       }
     }
     return clone;
   }
 }

深克隆实现机制相对复杂、效率稍慢,但它克服了浅克隆方式的不足,使得克隆对象时将类中的引用类型数据完全克隆为新的对象,而不是引用原本中的对象。如此,在修改双方的引用类型对象的数据时不会对另一方造成干扰。

但为每一个类都实现克隆方式,而重复书写相同代码未免麻烦。因此引入泛型方法。

3、泛型方法实现克隆

泛型的出现使得可以良好的解决在多个类或结构体中都需要进行克隆时重复编写代码的麻烦。在外部只需要使用相关方法即可。其代码如下:

public class Clone
 {
   /// <summary>
   /// 深克隆
   /// </summary>
   /// <typeparam name="T"></typeparam>
   /// <param name="t"></param>
   /// <returns></returns>
   public static T DepthClone<T>(T t)
   {
     T clone = default(T);
     using (Stream stream = new MemoryStream())
     {
       IFormatter formatter = new BinaryFormatter();
       try
       {
         formatter.Serialize(stream, t);
         stream.Seek(0, SeekOrigin.Begin);
         clone = (T)formatter.Deserialize(stream);
       }
       catch (SerializationException e)
       {
         Console.WriteLine("Failed to serialize. Reason: " + e.Message);
         throw;
       }
     }
     return clone;
   }
 }

在外部使用的方法如下:

 Student stu1 = new Student();//实例化一个对象
 stu1.obj = new object();//实例化对象中的引用对象
 Student stu2 = Clone.DepthClone(stu1);//深克隆对象

4、扩展方法

扩展方法的出现可以很好的解决类自身直接调用克隆方法,而不需要调用静态类的方法,返回对象值。但其本身与泛型方法类似,不过为了使所有类都能使用定义的深克隆方法,此处使用对顶级类Object进行方法的扩展,其返回的值也是object类型。具体方法如下:

/// <summary>
 /// 注:扩展方法必须在静态类中
 /// </summary>
 public static class Clone
 {
   /// <summary>
   /// 深克隆
   /// </summary>
   /// <param name="obj">原始版本对象</param>
   /// <returns>深克隆后的对象</returns>
   public static object DepthClone(this object obj)
   {
     object clone = new object();
     using (Stream stream = new MemoryStream())
     {
       IFormatter formatter = new BinaryFormatter();
       try
       {
         formatter.Serialize(stream, obj);
         stream.Seek(0, SeekOrigin.Begin);
         clone = formatter.Deserialize(stream);
       }
       catch (SerializationException e)
       {
         Console.WriteLine("Failed to serialize. Reason: " + e.Message);
         throw;
       }
     }
     return clone;
   }
 }

使用方法示例:

 Student stu1 = new Student();//实例化一个对象
 stu1.obj = new object();//实例化对象中的引用对象
 Student stu2 = stu1.DepthClone() as Student;//深克隆对象;注意:在此需要将object对象转换为我们需要的对象类型

以上就是详解 c# 克隆的详细内容,更多关于c# 克隆的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
  • 详解c# 深克隆与浅克隆
  • C# List引用类型克隆的3种方法
  • 浅析C#的复制和克隆
  • C# 调用腾讯即时通信 IM的示例
  • C# 实现简易的串口监视上位机功能附源码下载
  • c# 类型的字段和方法设计建议
  • C# 设置防火墙的创建规则
  • C# 进行图片压缩的示例代码(对jpg压缩效果最好)
  • c# Parallel类的使用

相关文章

  • 详解 c# 克隆

    详解 c# 克隆

    克隆方法是原型设计模式中必须使用的方式,它将返回一个与当前对象数据一致的对象。正如其名,犹如一个模子雕刻而出。克隆类型分为两种:浅克隆、深克隆。 1、浅克隆
    2020-11-21
  • 利用nexus作为私库进行代理docker,进行上传和下载镜像操作

    利用nexus作为私库进行代理docker,进行上传和下载镜像操作

    一、nexus的配置 1.创建docker proxy 用于从外网仓库中拉取镜像至本地仓库中。 点击“create Repository”,选择docker(proxy)进行创建 填写参数 点击“create re
    2020-11-21
  • gradle项目中资源文件的相对路径打包技巧必看

    gradle项目中资源文件的相对路径打包技巧必看

    开发java application时,不管是用ant/maven/gradle中的哪种方式来构建,通常最后都会打包成一个可执行的jar包程序,而程序运行所需的一些资源文件(配置文件),比如
    2020-11-21
  • Python如何批量生成和调用变量

    Python如何批量生成和调用变量

    这几天写代码中遇到的一个常见问题,在Python中如何批量的生成一些变量,如生成变量X1, X2, X3,并在后续的方法中调用,完成赋值、取值等操作。这个问题也算是常见的
    2020-11-21
  • 解决android报错:Intel HAXM is required to run this AVD

    解决android报错:Intel HAXM is required to run this AVD

    今天,简单讲解Android 启动模拟器时,提示错误: Intel HAXM is required to run this AVD. VT-x is disabled in BIOS. Enable VT-x in your BIOS security settin
    2020-11-21
  • 解决docker run 或者 docker restart 启动镜像就自动退出

    解决docker run 或者 docker restart 启动镜像就自动退出

    执行命令:docker run --name centos8 -d centos /bin/bash,通过docker ps查看正在运行中容器,找不到centos8。 通过docker ps -a查看发现,centos8容器已经处于停
    2020-11-21
  • Docker容器时区调整操作

    Docker容器时区调整操作

    如何检查Docker容器时区是否与宿主机一致? 1、进入宿主机, 执行以下命令: # 查看宿主机时间 [root@localhost ~]# date 2018年 06月 27日 星期三 22:42:44 CST
    2020-11-21
  • python遍历路径破解表单的示例

    python遍历路径破解表单的示例

    首先是利用python遍历路径,采用字典爆破的形式,当然如果只是单纯的爆破路径,简单写一个多线程脚本就行了。这里考虑如何对爆破到的路径进行第二步利用,此处尝试对
    2020-11-21
  • Docker 使用nsenter工具进入容器的操作

    Docker 使用nsenter工具进入容器的操作

    在使用Docker容器的时候,利用nsenter工具会比较方便,如果我们的系统没有的话,那就需要我们自己来安装了 1.首先访问该网址找到最新版本的nsenter工具 2.然后下载
    2020-11-21
  • 解决Docker中的error during connect异常情况

    解决Docker中的error during connect异常情况

    刚开始接触Docker,遇到异常问题难免会手忙脚乱。没事的,学习就是这样子,在困难中不断地找到解决问题的方法,贵在坚持,加油! 来了来了,问题来了,不要慌,看下
    2020-11-21

最新评论