首页 > 编程语言 > C# 使用Dictionary复制克隆副本及比较是否相等
2020
12-10

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复制克隆副本及比较是否相等就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持自学编程网。

编程技巧