首页 > 编程语言 >C# 深拷贝和浅拷贝的区别

C# 深拷贝和浅拷贝的区别

时间:2023-08-22 15:46:05浏览次数:28  
标签:set string get C# 区别 拷贝 public Name

含义:深拷贝和浅拷贝最根本的区别在于是否真正获取一个对象的复制实体,而不是引用。假设B复制了A,修改A的时候,看B是否发生变化:
如果B跟着也变了,说明是浅拷贝,拿人手短!(修改堆内存中的同一个值)如果B没有改变,说明是深拷贝,自食其力!(修改堆内存中的不同的值)

浅拷贝(shallowCopy)只复制了原对象,没有开辟新的内存,修改复制后的对象,原数据会跟着改变。
public class Person 

  public int Age { get; set; }   
  public string Address { get; set; }   
public Name Name { get; set; }   
}   
public class Name   

   public Name(string frisName,string lastName)   
{   
    FristName = frisName; 
    LastName = lastName;   
}   
  public string FristName { get; set; }   
  public string LastName { get; set; }   
}


深拷贝(deepCopy)复制原对象后,开辟新的内存,修改复制后的对象,原数据不会改变。
在C#中,我们们有三种方法实现深拷贝
 1. 实现ICloneable接口,自定义拷贝功能。   ICloneable 接口,支持克隆,即用与现有实例相同的值创建类的新实例。   ICloneable 接口包含一个成员 Clone,它用于支持除 MemberwiseClone 所提供的克隆之外的克隆。Clone 既可作为深层副本实现,也可作为浅表副本实现。在深层副本中,所有的对象都是重复的;而在浅表副本中,只有顶级对象是重复的,并且顶级以下的对象    包含引用。 结果克隆必须与原始实例具有相同的类型或是原始实例的兼容类型。   代码实现如下:
 public class Person:ICloneable  
 {   
  public int Age { get; set; }   
  public string Address { get; set; }   
  public Name Name { get; set; }   
  public object Clone()   
  {   
    Person tem = new Person();   
    tem.Address = this.Address;   
    tem.Age = this.Age;   
    tem.Name = new Name(this.Name.FristName, this.Name.LastName);   
    return tem;   
  }
 }   
  public class Name   
  {   
   public Name(string frisName, string lastName)   
   {   
    FristName = frisName;   
    LastName = lastName;   
   }   
   public string FristName { get; set; }   
   public string LastName { get; set; }   
}
大家可以看到,Person类继承了接口ICloneable并手动实现了其Clone方法,这是个简单的类,试想一下,如果你的类有成千上万个引用类型成员(当然太夸张,几十个还是有的),这是不是份很恐怖的劳力活?
2.序列化/反序列化类实现
  不知道你有没有注意到DataSet对象,对于他提供的两个方法:   DataSet.Clone 方法,复制 DataSet 的结构,包括所有 DataTable 架构、关系和约束。不要复制任何数据。   新 DataSet,其架构与当前 DataSet 的架构相同,但是不包含任何数据。注意 如果已创建这些类的子类,则复本也将属于相同的子类。   DataSet.Copy 方法复制该 DataSet 的结构和数据.   新的 DataSet,具有与该 DataSet 相同的结构(表架构、关系和约束)和数据。注意如果已创建这些类的子类,则副本也将属于相同的子类。   好像既不是浅拷贝,又不是深拷贝,是不是很失望?但是两个结合起来不是我们要的深拷贝吗?看看DataSet的实现,注意序列化接口:ISerializable   序列化是将对象或对象图形转换为线性字节序列,以存储或传输到另一个位置的过程。   反序列化是接受存储的信息并利用它重新创建对象的过程。   通过 ISerializable 接口,类可以执行其自己的序列化行为。   转换为线性字节序列后并利用其重新创建对象的过程是不是和我们的深拷贝的语意“逐位复制”很相像?   代码实现如下:  [Serializable]  public class Person : ICloneable     {      public int Age { get; set; }      public string Address { get; set; }      public Name Name { get; set; }      public object Clone()   {        using (MemoryStream ms = new MemoryStream(1000))        {        object CloneObject;        BinaryFormatter bf = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.Clone));        bf.Serialize(ms, this);        ms.Seek(0, SeekOrigin.Begin);        // 反序列化至另一个对象(即创建了一个原对象的深表副本)        CloneObject = bf.Deserialize(ms);        // 关闭流        ms.Close();         return CloneObject;        }      }     }      [Serializable]      public class Name      {        public Name(string frisName, string lastName)       {        FristName = frisName;        LastName = lastName;       }      public string FristName { get; set; }      public string LastName { get; set; }       }    } 注意:通过序列化和反序列化实现深拷贝,其和其字段类型必须标记为可序列化类型,既添加特性(Attribute)[Serializable]。 3.通过反射实现,  通过序列化/反序列化方式我们能比较流畅的实现深拷贝,但是涉及到IO操作,托管的的环境中,IO操作比较消耗资源。 能不能有更优雅的解决方案。CreateInstance,对,利用反射特性。这个方法大家可以参考这篇博客:http://rubenhak.com/?p=70 文章反射类   的Attribute,利用Activator.CreateInstance New一个类出来(有点像DataSet.Clone先获得架构),然后利用PropertyInfo的SetValue和GetValue方法,遍历的方式进行值填充。   代码实现如下:   public class Person      {        private List _friends = new List();        public string Firstname { get; set; }        public string Lastname { get; set; }               [Cloneable(CloneableState.Exclude)]          [Cloneable(CloneableState.Include, "Friends")]            public List Friends { get { return _friends; } }          [Cloneable(CloneableState.Exclude)]        public PersonManager Manager { get; set; }      }      部分内容转载:https://www.cnblogs.com/devgis/p/16418588.html

标签:set,string,get,C#,区别,拷贝,public,Name
From: https://www.cnblogs.com/KevinSteven/p/17648582.html

相关文章

  • CompletableFuture
    @SneakyThrows@OverridepublicSpuVOqueryDetail(Longid){//1.查询spuSpuVOspuVO=spuMapper.queryInfoById(id);if(spuVO==null){//是否存在此商品thrownewMallException("商品已删除");......
  • java怎么设置定时任务(通过Executors.newScheduledThreadPool(1)方法)
    importjava.text.SimpleDateFormat;importjava.util.Date;importjava.util.concurrent.Executors;importjava.util.concurrent.ScheduledExecutorService;importjava.util.concurrent.TimeUnit;publicclassdingshi{publicstaticvoidmain(String[]args)......
  • ios开发之--UISearchDisplayController的简单使用
    控件就不介绍了,UISearchDisplayController就是把searbar和tableview结合到一块了,直接上代码:.h#import<UIKit/UIKit.h>@interfaceThirdViewController:UIViewController<UITableViewDelegate,UITableViewDataSource>{NSArray*_array;NSArray*_filterData;UI......
  • swift--使用 is 和 as 操作符来实现类型检查和转换 / AnyObject与Any的区别
    声明几个类://动物类classAnimal{}//陆地动物类classterricole:Animal{}//海洋动物类classSeaAnimals:Animal{}1,is用来做类型检查letcat=terricole()letfish=SeaAnimals()letarr=[cat,fish]foranima......
  • 代码简洁之道:对象转换神器MapStruct
    在我们日常开发的程序中,为了各层之间解耦,一般会定义不同的对象用来在不同层之间传递数据,比如xxxDTO、xxxVO、xxxQO,当在不同层之间传输数据时,不可避免地经常需要将这些对象进行相互转换。今天给大家介绍一个对象转换工具MapStruct,代码简洁安全、性能高,强烈推荐。MapStruct简介MapSt......
  • ios开发之--ios11适配:TableView的heightForHeaderInSection设置高度无效/UISearchBar
    更新到ios11,然后使用x-code9运行项目,发现tableview的-(CGFloat)tableView:(UITableView*)tableViewheightForHeaderInSection:(NSInteger)section方法不走,所以页面也华丽丽的变成了一排的cell,通过查看文档和资料,原来是ios11默认开启self-sizing,把这个属性关系即可,具体代码如下:sel......
  • swift--触摸(UITouch)事件(点击,移动,抬起)
    触摸事件:UITouch:一个手机第一次点击屏幕,会形成一个UITouch对象,知道离开销毁。表示触碰。UITouch对象能表明当前手指触碰的屏幕位置、状态,状态分为开始触碰、移动、离开。具体方法介绍如下:1.overridefunctouchesBegan(_touches:Set<UITouch>,withevent:UIEvent?)通知调用者当......
  • ios开发之--ZHPickView输出格式不出现 +0000
    这样写就不会输出+0000了NSDate*select=[_datePickerdate];NSDateFormatter*dateFormatter=[[NSDateFormatteralloc]init];[dateFormattersetDateFormat:@"yyyy-MM-ddHH:mm:ss"];_resultString=[dateFormatterstringFromDate:select];输出+0000的原因是_......
  • 生信:一起读官方文档 featureCounts 篇
    一起读官方文档featureCounts篇featureCounts介绍用于为高通量测序数据(例如RNA-seq、ChIP-seq、ATAC-seq等)计数读取(reads)与注释特征(例如基因、转录本)的重叠。它是Subread软件包的一部分,特别适用于RNA-seq数据的基因表达量分析。快速使用featureCounts\-a../genome/......
  • ios开发之--UIViewContentMode详解
    在开发当中有时会有这样的需求,将从服务器端下载下来的图片添加到imageView当中展示,但是下载下来的图片尺寸大小不固定,宽高也有可能不成比例如果直接设置imageView的image属性而不设置contentMode那么图片会默认填满整个容器,导致图片变形,影响美观.直接设置1个正方形的imageVi......