C#中的shallow copy 与deep copy(一)
来源:互联网 发布:苟利国家网络什么意思 编辑:程序博客网 时间:2024/04/29 22:50
背景
1. 一年前我用vb.net做一个饭工厂饭卡系统,在编码的过程中发现一个问题。
我有一个卡信息类Card:
public Class Card { string CardID; string CardNum; }
在修改卡信息时,我的做法是这样的:
-->读取选定卡的所有信息(假设为(Card)A)
-->载入到修改界面中
-->用户提交时如果通过输入检查,则新建一个卡对象{ new Card B=A },因为有很多信息不能修改,所以我用A 来初始化B
-->将界面的数据刷新到B中
-->A=B?保存B:不保存。
但是调试的时候惊恐的发现,无论怎么改都是相等的……
在单步中我发现B一修改,A也跟着修改了,当时没当回事自己在类中回了一个copy方法:
public Class Card { string CardID; string CardNum; pulic Card copy() { Card tempCard =new Card(); tempCard .CardIdD=this.CardIdD; tempCard .CardNum=this.CardNum; return tempCard; } }
其中比较对象相等时,我也写了一个方法,就是逐一比较属性,不相等就返回false.
2.这周调研报表在mvc4下的实现,本来找到一个很好的例子:MVC下实现水晶报表,以为搞定了,结果拿到多项目的解决方案中,跨项目取数据又出现问题,其原因是 数据是在Service层(Service是一个单独的项目)取到,以
List<TSource>ToList<TSource>(thisIEnumerable<TSource>source)方式返回数据。
我在View层(也是一个单独的项目)得到的List<TSource>放入用<TSource>支撑的报表中时,运行时发现数据放不进去,查阅很多资料我认为是这个方法是运行时提取数据的(延时加载),报表得到的是一个查询语句,但是View层没有能力访问数据库,所以得不到数据。
针对以上情况,我决定先把List<TSource>中数据取出来放在一个临时List中再传给水晶报表。
我完全可以用以前的方法来做,但是此次实体中有很多字段,要是每个查询结果的实体类中都用这样的clone函数,那简直是扯蛋……
所以此次我花了一天时间来研究C#中实现类值拷贝的方式,优雅地复制副本……
术语解释
这里引用网友Timothy的一段文字:(原文链接如下:http://www.cnblogs.com/haiyang1985/archive/2009/01/13/1375017.html)
"C#中有两种类型变量,一种 是值类型变量,一种是引用类型变量。对于前者,copy是属于全盘复制;而对于后者,一般的copy只是浅copy,相当于只传递一个引用指针一样。因此 对于后者进行真正copy的时候,也是最费事的,具体的说,必须为其实现ICloneable接口中提供的Clone方法。
浅拷贝(影子克隆):只复制对象的基本类型,对象类型,仍属于原来的引用.
深拷贝(深度克隆):不紧复制对象的基本类,同时也复制原对象中的对象.就是说完全是新对象产生的.
浅 拷贝和深拷贝之间的区别:浅拷贝是指将对象中的数值类型的字段拷贝到新的对象中,而对象中的引用型字段则指复制它的一个引用到目标对象。如果改变目标对象 中引用型字段的值他将反映在原是对象中,也就是说原始对象中对应的字段也会发生变化。深拷贝与浅拷贝不同的是对于引用的处理,深拷贝将会在新对象中创建一 个新的和原是对象中对应字段相同(内容相同)的字段,也就是说这个引用和原是对象的引用是不同的,我们在改变新对象中的这个字段的时候是不会影响到原始对 象中对应字段的内容。所以对于原型模式也有不同的两种处理方法:对象的浅拷贝和深拷贝。"
深拷贝的实现方法
using System;using System.Collections.Generic;using System.IO;using System.Linq;using System.Runtime.Serialization.Formatters.Binary;using System.Text;using System.Threading.Tasks;namespace Extensions{ public static class CloneObject { /// <summary> /// Deep clone a ClassObject (by magma) /// </summary> /// <typeparam name="T"></typeparam> /// <param name="a"></param> /// <returns></returns> public static T DeepClone<T>(this T a) { using (MemoryStream stream = new MemoryStream()) { BinaryFormatter formatter = new BinaryFormatter(); formatter.Serialize(stream, a); stream.Position = 0; return (T)formatter.Deserialize(stream); } } }}
using System;using System.Collections.Generic;using System.ComponentModel.DataAnnotations;using System.ComponentModel.DataAnnotations.Schema;using System.Data.Entity;using System.Linq;using System.Text;using System.Threading.Tasks;namespace Model{ [Serializable] public class UserInfoLog : Entity { public UserInfoLog() { Addate = DateTime.Now; Uddate = DateTime.Now; } [Key, DatabaseGenerated(DatabaseGeneratedOption.None)] public string Id { set; get; } [MaxLength(100)] [Required] public string Url { get; set; } public string ChainInfoId { get; set; } public virtual ChainInfo ChainInfo { get; set; } public string RecordId { get; set; } public string SysUserId { get; set; } public virtual UserInfo UserInfo { get; set; } public string EnterpriseId { get; set; } [MaxLength(100)] [Required] public string Ip { get; set; } [StringLength(50)] public string Remark { set; get; } public DateTime Addate { set; get; } [StringLength(20)] public string Aduser { set; get; } public DateTime Uddate { set; get; } [StringLength(20)] public string Uduser { set; get; } }}
在需要实现此方法的类上添加Extensions引用,那么在所有obeject及其子类中都会有CloneObject方法。下面是一个代码片段:
/// <summary> /// 返回报表请求的数据 /// </summary> [HttpPost] public void TransDateToReport() { //报表路径 this.HttpContext.Session["ReportPath"] = System.Web.HttpContext.Current.Server.MapPath("~/") + "Rpts//CrUserList.rpt"; //报表数据源猎取 List<UserInfo> UserList = roleInfoService.findAllUserInfo().ToList(); List<UserInfo> userTemp=new List<UserInfo>(); foreach (UserInfo element in UserList) { userTemp.Add(element.DeepClone<UserInfo>()); } this.HttpContext.Session["ReportSource"] = userTemp; }
一种优雅实现
最近看一本C#高级编程的书,里面有一种方法用来比较两个对象中非静态对象的值是否相等,而非比较引用,实现的思路很不错:它重写了类的ToString方法,以key/value 形式返回待比较的字段,然后直接比较两个对象的toString返回值即可,有关具体的实现方式等有时间再补上。
- C#中的shallow copy 与deep copy(一)
- Shallow Copy与Deep Copy
- shallow copy与deep copy
- Deep copy & Shallow copy
- Shallow copy & Deep copy
- cocoa Shallow Copy与Deep Copy
- Deep Copy and Shallow Copy
- deep copy vs shallow copy
- Deep Copy VS Shallow Copy
- Shallow Copy and Deep Copy
- shallow copy and deep copy
- Deep copy and shallow copy
- deep copy and shallow copy
- shallow & deep copy
- Shallow vs. deep copy
- 深拷贝与浅拷贝(Deep Copy and Shallow Copy)
- java 中 的 deep copy 与 shallow copy
- 深拷贝与浅拷贝(Deep Copy and Shallow Copy)
- JS操作数据库的实例代码
- iOS ARC和非ARC混编
- abstract and interface 区别
- ajax得到的数据赋值给js中的全局变量
- java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
- C#中的shallow copy 与deep copy(一)
- 3.5 CMMI3级——验证(Verification)
- Eclipse搭建Ruby集成开发环境
- 二分图最大匹配总结 -- 转自bin神
- 实用级反主动防御rootkit设计思路
- Copy List with Random Pointer
- C#获取串口完整名字
- UIViewController容器机理分析
- 用SSH登陆操作 IPAD