1. 程式人生 > >淺談C#中的序列化與反序列化

淺談C#中的序列化與反序列化

今天我利用這篇文章給大家講解一下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中序列化與反序列化的相關知識和使用,序列化和反序列化的相關知識還有很多,這裡所講的都是開發中常用到的。好了,今天的知識就分享到這裡