zoukankan      html  css  js  c++  java
  • 实现自定义类型的深拷贝

        第一次写技术博文,手生的很,水平也有限,有什么不对的地方大家多多指教。

      家都知道class是引用类型,如果将一个引用变量分配给另一个引用变量,那么这个赋值操作进行的是一个浅拷贝,这两个引用变量将指向内存中的同一个对象。 我们有这样一个类的赋值操作就是执行这样的操作。

    代码
    public class TestClass
        {
            
    private int _X;
            
    private int _Y;

            
    public TestClass(int x,int y)
            {
                
    this._X = x;
                
    this._Y = y;
            }

            
    public int X
            {
                
    set { this._X = value; }
            }
    }
    static void Main(string[] args)
         {
                TestClass class1 = new TestClass(11); 
                TestClass class2 = class1;
               class2.X = 2;
    }

    这样的情况下我们修改class2X值那么class1X的值也会跟着改变。

    有些情况下我们需要现有类实例的一个副本该怎么办呢?这时候就需要我们实现ICloneable接口了。

    ICloneable接口的定义如下:

    代码
    [ComVisible(true)]
        
    public interface ICloneable
        {
            
    // 摘要:
            
    //     Creates a new object that is a copy of the current instance.
            
    //
            
    // 返回结果:
            
    //     A new object that is a copy of this instance.
            object Clone();
    }

    ComVisible特性是设置是否允许COM客户端访问,我们这里不详细说。

          如果我们希望自己的自定义类提供深拷贝能力的话具体分两种情况,一种情况是我们的自定义类中不包含引用类型的变量;另一种情况当然就是包含引用类型的变量了。下面我们分别说明这两种情况。

       现在我们的TestClass类只有两个成员变量_X,_Y都是值类型的变量,值类型变量不包含指向实例的指针,它本身即包含了实例的所有内容,所以我们只需要实现ICloneable接口的Clone()方法在方法中依次复制每个值类型字段即可,Clone方法为

    public object Clone()
    {
                
    //因为我们的字段都是在构造器中赋值的,所以以相同的值构建一个新的实例即可
                return new TestClass(_X, _Y);
    }

    .net中所有的类型都最终继承自System.Object类型,所以我们可以继续改进上面的Clone方法,使用System.Object类型提供的受保护方法

    MemberwiseClone,该方法创建新的类型实例,并将字段设置为和this对象的字段相同,现在我们的字段都是值类型的所以该方法即可获得实例的单独副本。

    Clone方法修改为:

    public object Clone()
            {
              
    //逐个复制TestClass的每个字段
                return base.MemberwiseClone();
            }

    现在TestClass修改为:

    代码
    public class TestClass:ICloneable
        {
            
    private int _X;
            
    private int _Y;

            
    public TestClass(int x,int y)
            {
                
    this._X = x;
                
    this._Y = y;
            }

            
    public int X
            {
                
    set { this._X = value; }
            }

            
    public object Clone()
            {
              
    //逐个复制TestClass的每个字段
                return base.MemberwiseClone();
            }
     }

         这样我们就可以获得TestClass的单独副本了,如下所示:

    代码
    static void Main(string[] args)
         {
                TestClass class1 = new TestClass(11); 
                TestClass class2 = (TestClass)class1.Clone();
                
    //改变class2不影响class1
           class2.X = 2;
    }

         包含引用变量字段的类型,实现深拷贝的方式跟上面的方法类似,只是需要注意引用类型在栈中保存的是指向托管堆的指针所有直接赋值和MemberwiseClone方法都是把指针地址复制,实际上还是指向同一个实例。我们需要在Clone方法中用同样的值构建全新的类型实例并返回。



     
  • 相关阅读:
    【Gerrit】重磅! 2.x 版本升级到 3.x 版本
    【Linux】参数传递之xargs
    Sqlserver账号对应数据库
    限流:计数器、漏桶、令牌桶 三大算法的原理与实战(史上最全)
    C# 运行在ubuntu, linux系统,在linux系统使用HslCommunication组件,.net core发布到ubuntu系统
    使用nmap命令监控远程服务器指定端口状态
    MySQL使用脚本进行整库数据备份【表(结构+数据)、视图、函数、事件】
    MySQL自定义函数与存储过程的创建、使用、删除
    vue响应式的原理
    浏览器渲染机制
  • 原文地址:https://www.cnblogs.com/breezeli/p/1678645.html
Copyright © 2011-2022 走看看