今天我利用這篇文章給大家講解一下C#中的序列化與反序列化。這兩個概念我們再開發中經常用到,但是我們絕大部分只用到了其中的一部分,剩下的部分很多開發人員並不清楚,甚至可以說是不知道。因此我希望通過這篇文章能讓大家對序列化和反序列化的知識有更進一步的掌握。廢話不多說,開始進入正題。
一、什么是序列化/反序列化
在所有的開發語言中都存在序列化和反序列化這個概念,所謂的序列化就是把一個對象信息轉化為一個可以持久存儲的數據形式,經過轉化后就可以方便的保存和傳輸了,因此序列化主要用於平台之間的通訊。由於序列化我們可以反推出所謂的反序列化就是將持久存儲的數據還原為對象。
二、C#中的序列化/反序列化
在C#中我們經常會對Json和Xml進行序列化和反序列化,但是還存在一種序列化/反序列化,那就是將對象序列化為二進制文件,將二進制文件反序列化為對象。下面我會對這三種序列化和反序列化進行解釋。
1、Json
Json的英文全稱是JavaScript Object Notation,是一種輕量級的數據交換格式,完全獨立於語言的文本格式,易於人閱讀和編寫,同時也易於機器解析和生成。Json是目前互聯網中主流的交換格式,同時也是很多開發語言配置文件的主流格式。
在.Net中存在兩個類對Json進行處理,分別是DataContractJsonSerializer和JavaScriptSerializer,這兩種類的功能基本一致。DataContractJsonSerializer位於命名空間 System.Runtime.Serialization.Json下,他的特點是必須用DatContract以及DataMember屬性標記成員。JavaScriptSerializer位於命名空間System.Web.Script.Serialization下,通過名字和他所在的命名空間我們可以得知他主要用在網絡通信中,他可以序列化任何類型的對象。同樣.Net中也存在一個強大的第三方Json序列化/反序列化庫 Newtonsoft.Json,他比前兩個類用起來方便很多。下面我們對這三個序列化/反序列化的方式分別進行講解。
(1)DataContractJsonSerializer
首先我們需要在項目引用DataContractJsonSerializer所在的命名空間,這里主要注意的是我們不僅要在項目中添加System.Runtime.Serialization還需要添加引用System.ServiceModel.Web。將這兩個命名空間添加到命名空間后就可以在代碼中進入DataContractJsonSerializer的命名空間了。
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
引入命名空間后,我們開始編寫序列化類
1 [DataContract] 2 class Student 3 { 4 [DataMember] 5 public string Name { get; set; } 6 [DataMember] 7 public int Sex { get; set; } 8 [DataMember] 9 public int Age { get; set; } 10 [DataMember] 11 public Address Address { get; set; } 12 } 13
14 [DataContract] 15 class Address 16 { 17 [DataMember] 18 public string City { get; set; } 19 [DataMember] 20 public string Road { get; set; } 21 }
在上述代碼中,我們看到類的頭部添加了DataContract特性,以及在類的屬性上也增加了DataMenber特性,一旦一個類被聲明為DataCOntract時,就代表着該類可以被序列化,並且可以在服務端和客戶端傳輸。只有聲明為DataContract的類型的對象可以被傳送,而且只有成員屬性會被傳送,成員方法不會被傳送。默認情況下類中的所有成員屬性都不會被序列化傳輸出去,如果需要將成員數據傳輸出去就需要在屬性頭部加入DataMember。
下面我們就利用DataContractJsonSerializer對對象進行序列化和反序列化,代碼如下:
1 class Program 2 { 3 static void Main() 4 { 5 #region 對象轉Json字符串
6
7 var student = new Student 8 { 9 Name = "小魔王", 10 Age = 18, 11 Sex = 1, 12 Address = new Address 13 { 14 City = "SD", 15 Road = "JS"
16 } 17 }; 18
19 //利用WriteObject方法序列化Json
20 DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Student)); 21 var stream = new MemoryStream(); 22 serializer.WriteObject(stream, student); 23 var bytes = new byte[stream.Length]; 24 stream.Position = 0; 25 stream.Read(bytes, 0, (int)stream.Length); 26 var strJson = Encoding.UTF8.GetString(bytes); 27 Console.WriteLine(strJson); 28
29 #endregion
30
31 #region Json字符串轉對象
32
33 stream = new MemoryStream(Encoding.UTF8.GetBytes(strJson)); 34 student = (Student)serializer.ReadObject(stream); 35 Console.WriteLine($"Name:{student.Name}"); 36 Console.WriteLine($"Sex:{student.Sex}"); 37 Console.WriteLine($"Age:{student.Age}"); 38 Console.WriteLine($"Address:{student.Address.City}{student.Address.Road}"); 39
40 #endregion
41
42 Console.ReadKey(); 43 } 44 } 45
46 [DataContract] 47 class Student 48 { 49 [DataMember] 50 public string Name { get; set; } 51 [DataMember] 52 public int Sex { get; set; } 53 [DataMember] 54 public int Age { get; set; } 55 [DataMember] 56 public Address Address { get; set; } 57 } 58
59 [DataContract] 60 class Address 61 { 62 [DataMember] 63 public string City { get; set; } 64 [DataMember] 65 public string Road { get; set; } 66 }
結果:
(2)JavaScriptSerializer
我們利用前面定義的類,來看一下JavaScriptSerializer的使用方法,我們將前面定義的類中的DataContract和DataMember都去掉。我們如果要使用JavaScriptSerializer只需要引入System.Web.Script.Serialization命名空間即可。下面我們就利用JavaScriptSerializer對象進行序列化和反序列化,代碼如下:
1 static void Main() 2 { 3 #region 對象轉Json字符串
4
5 var student = new Student 6 { 7 Name = "小魔王", 8 Age = 18, 9 Sex = 1, 10 Address = new Address 11 { 12 City = "SD", 13 Road = "JS"
14 } 15 }; 16
17 //初始化
18 JavaScriptSerializer serializer = new JavaScriptSerializer(); 19 var strJson = serializer.Serialize(student); 20 Console.WriteLine(strJson); 21 #endregion
22
23 #region Json字符串轉對象
24
25 student = serializer.Deserialize<Student>(strJson); 26 Console.WriteLine($"Name:{student.Name}"); 27 Console.WriteLine($"Sex:{student.Sex}"); 28 Console.WriteLine($"Age:{student.Age}"); 29 Console.WriteLine($"Address:{student.Address.City}+{student.Address.Road}"); 30 #endregion
31
32 Console.ReadKey(); 33 } 34 } 35
36 class Student 37 { 38 public string Name { get; set; } 39 public int Sex { get; set; } 40 public int Age { get; set; } 41 public Address Address { get; set; } 42 } 43
44 class Address 45 { 46 public string City { get; set; } 47 public string Road { get; set; } 48 }
結果:
(3)Newtonsoft.Json
NewtonSoft.Json功能有很多,除了序列化和反序列化之外,還有 Linq To Json、Json Path、XML support等,我們這篇文章之講解其中的序列化和反序列化,使用NewtonSoft.Json前首先我們需要在nuget中搜索並安裝,安裝完成后引入NewtonSoft.Json,下面我么你來看一下具體使用:
1 class Program 2 { 3 static void Main() 4 { 5 #region 對象轉XML字符串
6
7 var student = new Student 8 { 9 Name = "小魔王", 10 Age = 18, 11 Sex = 1, 12 Address = new Address 13 { 14 City = "SD", 15 Road = "JS"
16 } 17 }; 18
19 //初始化
20 var strJson = JsonConvert.SerializeObject(student); 21 Console.WriteLine(strJson); 22 #endregion
23
24 #region Json字符串轉對象
25
26 student = JsonConvert.DeserializeObject<Student>(strJson); 27 Console.WriteLine($"Name:{student.Name}"); 28 Console.WriteLine($"Sex:{student.Sex}"); 29 Console.WriteLine($"Age:{student.Age}"); 30 Console.WriteLine($"Address:{student.Address.City}+{student.Address.Road}"); 31 #endregion
32
33 Console.ReadKey(); 34 } 35 } 36
37 class Student 38 { 39 public string Name { get; set; } 40 public int Sex { get; set; } 41 public int Age { get; set; } 42 public Address Address { get; set; } 43 } 44
45 class Address 46 { 47 public string City { get; set; } 48 public string Road { get; set; } 49 }
結果:
從代碼中我們可以看到 NewtonSoft.Json序列化和反序列化更加簡單,簡單到只需要一行代碼就可以完成。
2、XML
在Json還沒有出現之前,Xml是互聯網上常用的數據交換格式和規范。.net中提供XmlSerializer類將對象序列化為XML和將XML反序列化為對象,使用方法是首先實例化,然后調用序列化/反序列化方法。下面我們依然使用最開始定義的那個類,來看看XmlSerializer的使用。使用前我們需要引入using System.Xml.Serialization命名空間。
具體序列化與反序列化方法如下:
1 class Program 2 { 3 static void Main() 4 { 5 #region 對象轉XML字符串
6
7 var student = new Student 8 { 9 Name = "小魔王", 10 Age = 18, 11 Sex = 1, 12 Address = new Address 13 { 14 City = "SD", 15 Road = "JS"
16 } 17 }; 18
19 //初始化
20 XmlSerializer xmlSerializer = new XmlSerializer(typeof(Student)); 21 using (var fs = new FileStream(@"F:\123.xml", FileMode.OpenOrCreate)) 22 { 23 xmlSerializer.Serialize(fs, student); 24 } 25 Console.WriteLine("序列化完成"); 26 #endregion
27
28 #region Json字符串轉對象
29
30 using (var fs = new FileStream(@"F:\123.xml", FileMode.OpenOrCreate)) 31 { 32 //XmlReader xmlReader = new XmlTextReader(fs); 33 //student = xmlSerializer.Deserialize(xmlReader) as Student;
34 student = xmlSerializer.Deserialize(fs) as Student; 35 } 36 Console.WriteLine($"Name:{student.Name}"); 37 Console.WriteLine($"Sex:{student.Sex}"); 38 Console.WriteLine($"Age:{student.Age}"); 39 Console.WriteLine($"Address:{student.Address.City}+{student.Address.Road}"); 40 #endregion
41
42 Console.ReadKey(); 43 } 44 } 45
46 public class Student 47 { 48 public string Name { get; set; } 49 public int Sex { get; set; } 50 public int Age { get; set; } 51 public Address Address { get; set; } 52 } 53
54 public class Address 55 { 56 public string City { get; set; } 57 public string Road { get; set; } 58 }
結果:
3、二進制
序列化為二進制,在實際開發中真有不少用到,但是我覺得還是有必要講一講,他的使用方法和XmlSerializer序列化/反序列化類似,首先實例化,然后調用序列化/反序列化方法。在進行序列化/反序列化前,首先引入命名空間System.Runtime.Serialization.Formatters.Binary,同時修改對象類如下:
1 [Serializable] 2 public class Student 3 { 4 public string Name { get; set; } 5 public int Sex { get; set; } 6 public int Age { get; set; } 7 public Address Address { get; set; } 8 } 9
10 [Serializable] 11 public class Address 12 { 13 public string City { get; set; } 14 public string Road { get; set; } 15 }
上述代碼中我們在類的頭部加入了Serializable特性,這代表着整個類對象都需要序列化,如果我們不需要序列化其中的某個屬性的話,只需要在該屬性上加上NonSerialized特性即可,下面我們來看一下序列化/反序列化代碼:
1 class Program 2 { 3 static void Main() 4 { 5 #region 對象轉XML字符串
6
7 var student = new Student 8 { 9 Name = "小魔王", 10 Age = 18, 11 Sex = 1, 12 Address = new Address 13 { 14 City = "SD", 15 Road = "JS"
16 } 17 }; 18
19 BinaryFormatter binaryFormatter = new BinaryFormatter(); 20 string fileName = Path.Combine(@"F:\", @"123.txt"); 21 using (var stream = new FileStream(fileName, FileMode.OpenOrCreate)) 22 { 23 binaryFormatter.Serialize(stream, student); 24 } 25 Console.WriteLine("序列化完成"); 26 #endregion
27
28 #region 字符串轉對象
29
30 using (var fs = new FileStream(@"F:\123.txt", FileMode.OpenOrCreate)) 31 { 32 student = binaryFormatter.Deserialize(fs) as Student; 33 } 34 Console.WriteLine($"Name:{student.Name}"); 35 Console.WriteLine($"Sex:{student.Sex}"); 36 Console.WriteLine($"Age:{student.Age}"); 37 Console.WriteLine($"Address:{student.Address.City}+{student.Address.Road}"); 38 #endregion
39
40 Console.ReadKey(); 41 } 42 } 43
44 [Serializable] 45 public class Student 46 { 47 public string Name { get; set; } 48 public int Sex { get; set; } 49 public int Age { get; set; } 50 public Address Address { get; set; } 51 } 52
53 [Serializable] 54 public class Address 55 { 56 public string City { get; set; } 57 public string Road { get; set; } 58 }
這篇文章詳細的講述了.Net中序列化與反序列化的相關知識和使用,序列化和反序列化的相關知識還有很多,這里所講的都是開發中常用到的。好了,今天的知識就分享到這里了。