C# 使用Dictionary复制克隆副本及比较是否相等

一、复制克隆

用等号直接Dictionary1 = Dictionary2,复制过去的是地址(赋址),这时改变Dictionary2,Dictionary1也会被改变。普遍的是我们常常在改变复制后的值时不希望改变原有的值。这时就需要赋值而不是赋址。可用下列方法进行赋值:

private void Test()
{
 Dictionary<string, string> dic = new Dictionary<string, string> { { "A", "a" }, { "B", "b" } };
 //方法一
 Dictionary<string, string> dic1 = new Dictionary<string, string>(dic);
 //方法二
 Dictionary<string, string> dic2 = Clone(dic) as Dictionary<string, string>;
 //方法三 --需要引用Newtonsoft.Json.dll
 Dictionary<string, string> dic3 = JsonConvert.DeserializeObject<Dictionary<string, string>>(JsonConvert.SerializeObject(dic2));
}

采用序列化和反序列化

/// <summary>
/// 得到一个对象的克隆(二进制的序列化和反序列化)--需要标记可序列化
/// </summary>
public static object Clone(object obj)
{
 MemoryStream memoryStream = new MemoryStream();
 BinaryFormatter formatter = new BinaryFormatter();
 formatter.Serialize(memoryStream, obj);
 memoryStream.Position = 0;
 return formatter.Deserialize(memoryStream);
}

当值为引用类型时

[Serializable]
public class People : IEquatable<People>
{
 public string Name { get; set; }
 public int Age { get; set; }
 public bool Equals(People other)
 {
  if (other is null)
   return false;
  return this.Name == other.Name && this.Age == other.Age;
 }
}

private void Test()
{
 Dictionary<string, People> dic = new Dictionary<string, People> { { "A", new People {Name="SD",Age=0 } }, { "B", new People { Name = "FD", Age = 1 } } };
 //方法一
 Dictionary<string, People> dic2 = Clone(dic) as Dictionary<string, People>;
 //方法二 --需要引用Newtonsoft.Json.dll
 Dictionary<string, People> dic3 = JsonConvert.DeserializeObject<Dictionary<string, People>>(JsonConvert.SerializeObject(dic2));
}

二、比较两个Dictionary是否相等

/// <summary>
/// 比较
/// </summary>
private void Test()
{
 Dictionary<string, object> dic = new Dictionary<string, object> { { "A", 1 }, { "B", "b" } };
 Dictionary<string, object> dic2 = new Dictionary<string, object> { { "A", 1 }, { "B", "b" } };
 var a = dic.Equals(dic2); //结果 false
 var b = dic.SequenceEqual(dic2); //结果 true
}

补充知识:C#中的深复制和浅复制(在C#中克隆对象)

C# 支持两种类型:“值类型”和“引用类型”。

值类型(Value Type)(如 char、int 和 float)、枚举类型和结构类型。

引用类型(Reference Type) 包括类 (Class) 类型、接口类型、委托类型和数组类型。

如何来划分它们?

以它们在计算机内存中如何分配来划分

值类型与引用类型的区别?

1,值类型的变量直接包含其数据,

2,引用类型的变量则存储对象引用。

对于引用类型,两个变量可能引用同一个对象,因此对一个变量的操作可能影响另一个变量所引用的对象。对于值类型,每个变量都有自己的数据副本,对一个变量的操作不可能影响另一个变量。

值类型隐式继承自System.ValueType 所以不能显示让一个结构继承一个类,C#不支持多继承

堆栈(stack)是一种先进先出的数据结构,在内存中,变量会被分配在堆栈上来进行操作。

堆(heap)是用于为类型实例(对象)分配空间的内存区域,在堆上创建一个对象,

会将对象的地址传给堆栈上的变量(反过来叫变量指向此对象,或者变量引用此对象)。

关于对象克隆的所设计到知识点

浅拷贝:

是指将对象中的所有字段逐字复杂到一个新对象

对值类型字段只是简单的拷贝一个副本到目标对象,改变目标对象中值类型字段的值不会反映到原始对象中,因为拷贝的是副本

对引用型字段则是指拷贝他的一个引用到目标对象。改变目标对象中引用类型字段的值它将反映到原始对象中,因为拷贝的是指向堆是上的一个地址

深拷贝:

深拷贝与浅拷贝不同的是对于引用字段的处理,深拷贝将会在新对象中创建一个新的对象和原始对象中对应字段相同(内容相同)的字段,也就是说这个引用和原始对象的引用是不同, 我们改变新

对象中这个字段的时候是不会影响到原始对象中对应字段的内容。

浅复制: 实现浅复制需要使用Object类的MemberwiseClone方法用于创建一个浅表副本

深复制: 须实现 ICloneable接口中的Clone方法,且需要需要克隆的对象加上[Serializable]特性

namespace DeepCopy
{
 class DrawBase : System.Object, ICloneable
 {
  public List<string> listName = new List<string>();
  public string name = "old";
  public DrawBase()
  {
  }
  public object Clone()
  {
   //任选一个
   return this as object;  //引用同一个对象
   //return this.MemberwiseClone(); //浅复制
   //return new DrawBase() as object;//深复制
  }
 }
 class Program
 {
  static void Main(string[] args)
  {
   DrawBase rect = new DrawBase();
   Console.WriteLine(rect.name);
   DrawBase line = rect.Clone() as DrawBase;
   line.name = "new";
   line.listName.Add("123");
   Console.WriteLine(rect.name);
   Console.WriteLine(rect.listName.Count);
   Console.ReadLine();
  }
 }
}

当return this as object;

输出:old,new,1

说明:方法总是引用同一个对象,因此相应的堆内存上的值会改变

当return this.MemberwiseClone();

输出:old,old,1

说明:对于内部的Class的对象和数组,会Copy地址一份。[从而改变B时,A也被改变了]而对于其它内置的int/string/Enum/struct/object类型,则进行值copy。

当return new DrawBase() as object;

输出:old,old,0

说明:完全是创建一个新对象

总结:

浅拷贝:是指将对象中的所有字段逐字复杂到一个新对象。

对值类型字段只是简单的拷贝一个副本到目标对象,改变目标对象中值类型字段的值不会反映到原始对象中,因为拷贝的是副本;

对引用型字段则是指拷贝他的一个引用到目标对象。改变目标对象中引用类型字段的值它将反映到原始对象中,因为拷贝的是指向堆是上的一个地址;

深拷贝:深拷贝与浅拷贝不同的是对于引用字段的处理,深拷贝将会在新对象中创建一个新的对象和原始对象中对应字段相同(内容相同)的字段,也就是说这个引用和原始对象的引用是不同, 我们改变新对象中这个字段的时候是不会影响到原始对象中对应字段的内容。

以上这篇C# 使用Dictionary复制克隆副本及比较是否相等就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • C# ArrayList、HashSet、HashTable、List、Dictionary的区别详解

    在C#中,数组由于是固定长度的,所以常常不能满足我们开发的需求. 由于这种限制不方便,所以出现了ArrayList. ArrayList.List<T> ArrayList是可变长数组,你可以将任意多的数据Add到ArrayList里面.其内部维护的数组,当长度不足时,会自动扩容为原来的两倍. 但是ArrayList也有一个缺点,就是存入ArrayList里面的数据都是Object类型的,所以如果将值类型存入和取出的时候会发生装箱.拆箱操作(就是值类型与引用类型之间的转换),这个会影响程序性能

  • c# 遍历 Dictionary的四种方式

    一:背景 1. 讲故事 昨天在 StackOverflow 上看到一个很有趣的问题,说: 你会几种遍历字典的方式,然后跟帖就是各种奇葩的回答,挺有意思,马上就要国庆了,娱乐娱乐吧,说说这种挺无聊的问题

  • Lua Table转C# Dictionary的方法示例

    table特性 table是一个"关联数组",数组的索引可以是数字或者是字符串,所有索引值都需要用 "["和"]" 括起来:如果是字符串,还可以去掉引号和中括号: 即如果没有[]括起,则认为是字符串索引 table 的默认初始索引一般以 1 开始,如果不写索引,则索引就会被认为是数字,并按顺序自动从1往后编: table 的变量只是一个地址引用,对 table 的操作不会产生数据影响 table 不会固定长度大小,有新数据插入时长度会自动增长 t

  • C#存储相同键多个值的Dictionary实例详解

    涉及到两个问题: 一.访问磁盘中文件夹.文件夹下面的文件夹 先看一下磁盘文件夹结构 C盘下面有个根文件夹SaveFile,SaveFIle下面有两个子文件夹分别为,2018.2019, 子文件下2018下面有两个子文件夹18120和18131 子文件下2019下面有两个子文件夹18120和18129 现在希望把SaveFile子文件夹和子文件夹下面的文件夹的名称存起来,也就是下面这样的 2018       18120     18131 2019 18120 18129 二.基于以上的结构我们

  • C# Dictionary和SortedDictionary的简介

    1.SortedDictionary 泛型类 SortedDictionary 泛型类是检索运算复杂度为 O(log n) 的二叉搜索树,其中 n 是字典中的元素数.就这一点而言,它与 SortedList 泛型类相似.这两个类具有相似的对象模型,并且都具有 O(log n) 的检索运算复杂度.这两个类的区别在于内存的使用以及插入和移除元素的速度: SortedList 使用的内存比 SortedDictionary 少. SortedDictionary 可对未排序的数据执行更快的插入和移除操

  • 详解 c# 克隆

    克隆方法是原型设计模式中必须使用的方式,它将返回一个与当前对象数据一致的对象.正如其名,犹如一个模子雕刻而出.克隆类型分为两种:浅克隆.深克隆. 1.浅克隆 浅克隆方式是最简单.最直接的方式.只需要类实现接口ICloneable(在命名空间System.Runtime.InteropServices下)的Clone方法,在方法中使用加入对当前类的MemberwiseClone()方法即可.在浅克隆中,如果原型对象的成员变量是值类型,将复制一份给克隆对象:如果原型对象的成员变量是引用类型,则将引用

  • C# 使用Dictionary复制克隆副本及比较是否相等

    一.复制克隆 用等号直接Dictionary1 = Dictionary2,复制过去的是地址(赋址),这时改变Dictionary2,Dictionary1也会被改变.普遍的是我们常常在改变复制后的值时不希望改变原有的值.这时就需要赋值而不是赋址.可用下列方法进行赋值: private void Test() { Dictionary<string, string> dic = new Dictionary<string, string> { { "A", &q

  • MongoDB 复制(副本集)学习笔记

    本文实例讲述了MongoDB 复制(副本集).分享给大家供大家参考,具体如下: replication set复制集, 复制集,多台服务器维护相同的数据副本,提高服务器的可用性. MongoDB复制是将数据同步在多个服务器的过程. 复制提供了数据的冗余备份,并在多个服务器上存储数据副本,提高了数据的可用性, 并可以保证数据的安全性. 复制还允许您从硬件故障和服务中断中恢复数据. 设置过程: (1)创建示例 假设创建三台,创建三个实例目录和日志目录: mkdir /home/m17 /home/m

  • 解决Python使用列表副本的问题

    要使用一个列表的副本,要用切片进行列表复制,这样会形成两个独立的列表. 切记不要将列表赋值给一个列表,因为这样并不能得到两个列表. 1.使用赋值语法创建列表副本的问题 下边就将列表赋值,验证是否形成独立的列表: squares = list(range(1, 11)) print('squares原始值为:', end='') print(squares) # 使用列表赋值 numbers_squares = squares print('numbers_squares所有元素为:', end=

  • 利用Java反射机制实现对象相同字段的复制操作

    一.如何实现不同类型对象之间的复制问题? 1.为什么会有这个问题? 近来在进行一个项目开发的时候,为了隐藏后端数据库表结构.同时也为了配合给前端一个更友好的API接口文档(swagger API文档),我采用POJO来对应数据表结构,使用VO来给传递前端要展示的数据,同时使用DTO来进行请求参数的封装.以上是一个具体的场景,可以发现这样子一个现象:POJO.VO.DTO对象是同一个数据的不同视图,所以会有很多相同的字段,由于不同的地方使用不同的对象,无可避免的会存在对象之间的值迁移问题,迁移的一

  • Mootools 1.2教程 排序类和方法简介

    Sortables类还提供了包括一个名叫"serialize"的优秀方法,通过这个方法你额可以把这些元素的id作为数组输出--对于服务器端的开发非常有用.接下来,我们看看如何创建一个新的排序项集合,还有一定要看一下最后的演示实例. 基本知识 创建一个新的Sortable对象 首先,我们要把我们要排序的元素赋值给变量.对于Sortables来说,如果你想要多个列表之间的元素能够在相互之间拖拽,你需要把这些元素全部都放在一个数组中,就像这样: 参考代码: 复制代码 代码如下: var so

  • Backbone.js 0.9.2 源码注释中文翻译版

    // Backbone.js 0.9.2 // (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc. // Backbone may be freely distributed under the MIT license. // For all details and documentation: // http://backbonejs.org (function() { // 创建一个全局对象, 在浏览器中表示为window对象, 在Node.j

  • Python中字典和集合学习小结

    映射类型: 表示一个任意对象的集合,且可以通过另一个几乎是任意键值的集合进行索引 与序列不同,映射是无序的,通过键进行索引 任何不可变对象都可用作字典的键,如字符串.数字.元组等 包含可变对象的列表.字典和元组不能用作键 引用不存在的键会引发KeyError异常 1)字典 dict { } 空字典 { key1:value1,key2:value2,... } 字典在其它编程语言中又称作关联数组或散列表: 通过键实现元素存取:无序集合:可变类型容器,长度可变,异构,嵌套 支持的操作: len(D

  • C# 设计模式系列教程-原型模式

    1. 概述 通过复制一个已经存在的实例来创建一个新的实例.被复制的实例被称为原型,这个原型是可定制的. 2. 模式中的角色 2.1 抽象原型类(Abstract Prototype):提供一个克隆接口 2.2 具体原型类(Concrete Prototype): 及实现了克隆接口的具体原型类 3. 实例:求职网站上现在都支持多份简历,如果每创建一份简历都要从头至尾地填写一遍,那也是非常让人沮丧的事.其实针对我们的求职岗位的不同,不同的简历可能只要修改局部内容就可以了,而不用全部重新构建一份新的简

  • JS是按值传递还是按引用传递

    按值传递 VS. 按引用传递 按值传递(call by value)是最常用的求值策略:函数的形参是被调用时所传实参的副本.修改形参的值并不会影响实参.   按引用传递(call by reference)时,函数的形参接收实参的隐式引用,而不再是副本.这意味着函数形参的值如果被修改,实参也会被修改.同时两者指向相同的值.   按引用传递会使函数调用的追踪更加困难,有时也会引起一些微妙的BUG.   按值传递由于每次都需要克隆副本,对一些复杂类型,性能较低.两种传值方式都有各自的问题.   我们

  • JavaScript中的值是按值传递还是按引用传递问题探讨

    最近遇到个有趣的问题:"JS中的值是按值传递,还是按引用传递呢?"   在分析这个问题之前,我们需了解什么是按值传递(call by value),什么是按引用传递(call by reference).在计算机科学里,这个部分叫求值策略(Evaluation Strategy).它决定变量之间.函数调用时实参和形参之间值是如何传递的.   按值传递 VS. 按引用传递 按值传递(call by value)是最常用的求值策略:函数的形参是被调用时所传实参的副本.修改形参的值并不会影响

随机推荐