C# 浅复制和深复制
来源:互联网 发布:薛之谦的淘宝女装店 编辑:程序博客网 时间:2024/06/06 23:56
Hi all,
其实最近一直在做WPF的项目,关于UI,MVVM,多线程,devexpress都想写些东西,可惜忙着,虽然平时感悟挺深,也来不及整理,
也不想随便写写忽悠大家,毕竟不是那种随便写写都能写出好文的大神,只是想好好的分享下项目过程中遇到的一些容易放错的地方,俗话说
“知错能改”嘛。
嘻嘻,其实这篇也是忽悠,只是今天在写复杂function时遇到而已,一时没注意就错了都不知道。
以下仅个人理解加某些专业术语,有不对的地方请原谅。
“浅复制是对引用类型地址的复制,而深复制是对值类型的复制。”
这句话有两个个名词,
值类型:派生自System.ValueType的类型,我们常见的 int char long struct short 等等的数值或结构体或enum,
引用类型:派生自System.object的类型,如 string 数组array 类class list 等高级的数据类型。
文字不好说,还是直接上代码说明:(一个极简的CLI程序)
string aaa = "have"; string bbb = aaa; bbb = bbb + "_lin"; Console.WriteLine(aaa);
这个例子有点特殊,故意举例这个的,虽说string是引用类型,但是在等号复制的过程中还是“深复制”,具体原因查过资料才知道:
//表示空字符串。此字段为只读。
public static readonly string Empty;
答案就在于 string 是 readonly 的,当改变 string 类型的数据值时,将重新分配了内存地址。
我们举另一个例子List类型:
List<string> arr1 = new List<string>(); arr1.Add("1"); arr1.Add("2"); arr1.Add("3"); var arr2 = arr1; arr2[1] = "lin"; foreach(string s in arr1) { Console.WriteLine(s); }
结果是:“1” “lin” "3" ,
上面的程序中,我们修改的是arr2,但arr1也同时被修改了,这说明arr1和arr2是使用一个值的,这就是引用类型的特点。
最后说明注意场景,例子仅自己今天遇到的,还是直接上代码(有点长):
小结,在写长代码片段是,对临时变量的管理特重要,在这个例子中,因为要对新对象处理,对旧对象使用检索,
所以不能让新对象影响旧对象,看上去自然的逻辑,其实上错在仅仅的一行代码,这是很冤枉的。
best regards
希望能腾点时间来写wpf的专题。
补充1:
很不幸,真的只能说是技术没到家:。
对于List这样的集合,提供了支持深复制的方法,GetRange,还是直接上代码:
List<string> arr1 = new List<string>(); arr1.Add("1"); arr1.Add("2"); arr1.Add("3"); var arr2 = arr1; changeList(arr2.GetRange(0, arr2.Count)); arr2[1] = "lin"; foreach (string s in arr1) { Console.WriteLine(s); }private static void changeList(List<string> list) { if (list.Count != 0) { list[0] = "haha"; } }
最后结果是:‘1’ ‘lin’ ‘3’
代码里头有两处地方修改List,分别是index 0和1,但最终只有index 1改变,为此,说明GetRange方法是对arr2对象的一个深复制。
回过头来写这一段,也是为了指出之前犯的错误(CTO跟我说你那个函数迟早会有问题),我才痛定思痛的看了不知道多少遍,
直接上代码说明:
Model层数据
//使用localDB连接数据库获取数据 public static Player[] GetPlayerByRegionId(Guid regionId) { using (var dbContext = new LocalModel()) { var players = (from p in dbContext.Players where p.RegionId == regionId select p).ToArray(); return players; } }
Control层调用
private void Sample1(Guid regionId) { var players1 = LocalDBAccess.GetPlayerByRegionId(regionId); List<Player> FirstListObj = new List<Player>(players1); //接下来是复制对象部分,先举错误示例, //用我上面的方法获取一个相同的对象,做法是这样 var playeres2 = LocalDBAccess.GetPlayerByRegionId(regionId); List<Player> LaterListObj = new List<Player>(playeres2); //然后各自操作 FirstListObj ,,LaterListObj ....... ....... }
在没有访问锁(访问限制)的数据库中,在user1执行完 GetPlayerByRegionId 方法后,来自user2 给 相关表添加一条数据,
那么用户再次执行 GetPlayerByRegionId 方法时,他获取到的 LaterListObj 就与FirstListObj 不一致,并没有实现复制的功能。
下面改变Control层调用
private void Sample2(Guid regionId) { var players1 = LocalDBAccess.GetPlayerByRegionId(regionId); List<Player> FirstListObj = new List<Player>(players1); //接下来是复制对象部分,正确示例, //使用GetRange方法,其他的集合对象也有类似的方法 var LaterListObj = FirstListObj.GetRange(0, FirstListObj.Count); //然后各自操作 FirstListObj ,,LaterListObj ...... ...... }
这里我们对数据连接只有一次,所以数据库的改变并不会马上反应到变量中,所有操作均是在基础数据上。
最后的最后,特意挖出来重新举例,一是承认自己的错,而勉励自己继续努力。
最后修改2017年3月31日11:15:39
- C#浅复制和深复制
- C#中的深复制和浅复制
- C# 浅复制和深复制
- C#中List的浅复制和深复制
- c#浅度复制和深度复制
- 深复制和浅复制
- 深复制和浅复制
- 深复制和浅复制
- 深复制和浅复制
- 深复制和浅复制
- 深复制和浅复制
- 深复制和浅复制
- 深复制和浅复制
- 深复制和浅复制
- 浅复制和深复制
- 浅复制和深复制
- 深复制和浅复制
- 深复制和浅复制
- 解决 make时报错 fatal error: ltdl.h: No such file or directory的方法
- PHP递归爆栈问题
- MVC框架的总结
- React Native打包发布--Android
- Android动态权限获取总结
- C# 浅复制和深复制
- 输入年月 打印相应星期
- html头部meta标签详解
- 面试
- 异步任务神器 Celery 快速入门
- Tinker接入详解
- HDFS文件读写过程
- 关于 Token,你应该知道的十件事
- leetcode第五周解题总结(138, 23)