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 } },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" } }; Dictionary<string,object> dic2 = new Dictionary<string,"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複製克隆副本及比較是否相等就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。