.NET中的序列化和反序列化详解

您所在的位置:网站首页 序列化和反序列化的原理一样吗 .NET中的序列化和反序列化详解

.NET中的序列化和反序列化详解

2024-07-10 23:59| 来源: 网络整理| 查看: 265

更新记录 本文迁移自Panda666原博客,原发布时间:2021年7月1日。

一、.NET中的序列化介绍 1.1序列化基础

序列化(Serialization),也叫串行化。通过将对象转换为字节流,从而存储对象到内存,数据库或文件的过程。主要用途是保存对象的状态数据,以便进行传输和需要时重建对象。对象的状态主要包括字段和属性(不包含方法和事件)。 image 反序列化(Deserialization):将序列化后的数据重新解析成类型的实例。

1.2序列化的作用

传递数据 保存数据(持久化数据)

1.3.NET中序列化的流程 将支持序列化的类型进行实例化成对象。 通过使用Formatter/Serializer将被序列化对象进行序列化编码。 然后存入指定的流中。

参与序列化过程的对象详细说明:

被序列化的对象 可以是一个对象,也可是一个集合 需要被序列化的类型需要使用SerializableAttribute 特性修饰 类型中不可序列化的成员需要使用NonSerializedAttribute 特性修饰

包含已序列化对象的流对象 比如:文件流、内存流

Fromatter/Serializer类型 用于给被序列化的对象进行序列化 序列化和反序列化对象所使用的Fromatter/Serializer主要是以下类型

System.Text.Json.JsonSerializer System.Xml.Serialization.XmlSerializer System.Runtime.Serialization.Formatters.Binary.BinaryFormatter System.Runtime.Serialization.DataContractSerializer System.Runtime.Serialization.Json.DataContractJsonSerializer 1.4序列化常用的底层格式

JSON(JavaScript Object Notation) 比较紧凑,适合用于传输 现在常用于Web传输数据

XML(eXtensible Markup Language) 表示数据更加直观,可读性更好 但也导致容量更大

Binary 在二进制序列化中,所有内容都会被序列化 使用二进制编码来生成精简的序列化 可以用于基于存储或socket的网络流

二、JSON序列化 2.1使用方法

使用方法相当简单,直接使用JsonSerializer静态类。 调用Serialize()静态方法进行序列化

JsonSerializer.Serialize()

调用Deserialize()静态方法进行反序列化

JsonSerializer.Deserialize() 2.2实例:序列化与反序列化 using System; using System.IO; using System.Text.Json; namespace Demo { /// /// 测试使用的类型 /// [Serializable] public class Student { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } } class Program { static void Main(string[] args) { //新建类型实例 Student student = new Student() { Id = 666, Name = "Panda", Age = 666666 }; //进行序列化 string serializeString = JsonSerializer.Serialize(student,typeof(Student)); Console.WriteLine(serializeString); //反序列化数据 Student deserializedData = (Student)JsonSerializer.Deserialize(serializeString, typeof(Student)); Console.WriteLine(deserializedData.Id); Console.WriteLine(deserializedData.Name); Console.WriteLine(deserializedData.Age); //wait Console.WriteLine("Success"); Console.ReadKey(); } } } 三、JSON序列化(数据协定) 3.1使用方法

引入命名空间

using System.Runtime.Serialization.Json;

使用DataContractJsonSerializer类型

DataContractJsonSerializer 3.2实例:序列化数据 using System; using System.IO; using System.Runtime.Serialization.Json; namespace ConsoleApp1 { /// /// 测试使用的类型 /// [Serializable] public class Student { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } } class Program { static void Main(string[] args) { //新建类型实例 Student student = new Student() { Id = 666, Name = "Panda", Age = 666666 }; //序列化数据 //新建文件流 string filePath = @"E:\新建文本文档.json"; using(FileStream fileStream = new FileStream(filePath,FileMode.OpenOrCreate)) { //新建序列化对象 DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(typeof(Student)); //进行序列化 dataContractJsonSerializer.WriteObject(fileStream, student); } //wait Console.WriteLine("Success"); Console.ReadKey(); } } } 3.3实例:反序列化数据 using System; using System.IO; using System.Runtime.Serialization.Json; namespace ConsoleApp1 { /// /// 测试使用的类型 /// [Serializable] public class Student { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } } class Program { static void Main(string[] args) { //新建类型实例 Student student = new Student() { Id = 666, Name = "Panda", Age = 666666 }; //序列化数据 //新建文件流 string filePath = @"E:\新建文本文档.json"; using(FileStream fileStream = new FileStream(filePath,FileMode.OpenOrCreate)) { //新建序列化对象 DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(typeof(Student)); //进行序列化 dataContractJsonSerializer.WriteObject(fileStream, student); } //反序列化数据 //新建文件流 using (FileStream fileStream1 = new FileStream(filePath, FileMode.Open)) { //新建序列化对象 DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(typeof(Student)); //进行反序列化 Student student1 = (Student)dataContractJsonSerializer.ReadObject(fileStream1); //读取反序列化后的对象 Console.WriteLine($"{student1.Id},{student1.Name},{student1.Age}"); } //wait Console.WriteLine("Success"); Console.ReadKey(); } } } 四、XML序列化 4.1使用方法

所在命名空间

using System.Xml.Serialization;

使用XmlSerializer类型

XmlSerializer

注意:该类型只序列化public成员,非公共成员会发生异常。 注意:需要被序列化的类型必须有无参数的构造函数。 自定义集合类型成员的XML元素名称,使用[XmlArray]特性修改该成员即可

[XmlArray] [XmlArrayItem] //注意:修饰在和[XmlArray]同一个成员上

自定义XML元素的名称,使用特性修饰成员即可

[XmlRoot("RootName")] 指定根节点标签名称 [XmlElement("EleName")] 指定元素名称

将成员转为XML特性,使用特性修饰成员即可

[XmlAttribute("AtrrName")]

自定义XML命名空间,使用Namespace成员即可

[XmlRoot("RootName",Namespace = "Panda")] [XmlAttribute("AtrrName", Namespace = "Panda")] [XmlElement("EleName", Namespace = "Panda")] 4.2实例:序列化为XML using System; using System.IO; using System.Xml.Serialization; namespace ConsoleApp1 { /// /// 测试使用的类型 /// [Serializable] public class Student { public int Id { get; set; } public string Name { get; set; } [NonSerialized] public int Age; } class Program { static void Main(string[] args) { //新建类型实例 Student student = new Student() { Id = 666, Name = "Panda", Age = 666666 }; //执行序列化 //创建文件流 string filePath = @"E:\xml.xml"; using(FileStream fileStream = new FileStream(filePath,FileMode.OpenOrCreate)) { //创建XML序列化对象 XmlSerializer xmlSerializer = new XmlSerializer(typeof(Student)); //执行序列化 xmlSerializer.Serialize(fileStream, student); } //执行反序列化 //创建文件流 using(FileStream fileStream1 = new FileStream(filePath,FileMode.Open)) { //创建XML序列化对象 XmlSerializer xmlSerializer = new XmlSerializer(typeof(Student)); //执行反序列化 Student data = (Student)xmlSerializer.Deserialize(fileStream1); //输出数据 Console.WriteLine($"{data.Id},{data.Name},{data.Age}"); } //wait Console.WriteLine("Success"); Console.ReadKey(); } } } 4.3实例:序列化为XML using System; using System.IO; using System.Collections.Generic; using System.Xml.Serialization; namespace ConsoleApp6 { //测试用的类型 public class Person { public Person() { } public Person(decimal initialSalary) { Salary = initialSalary; } public string FirstName { get; set; } public string LastName { get; set; } public DateTime DateOfBirth { get; set; } public HashSet Children { get; set; } protected decimal Salary { get; set; } } class Program { static void Main(string[] args) { //需要被序列化数据集合 List people = new List { new Person(30000M) { FirstName = "Alice",LastName = "Smith", DateOfBirth = new DateTime(1974, 3, 14) }, new Person(40000M) { FirstName = "Bob",LastName = "Jones", DateOfBirth = new DateTime(1969, 11, 23) }, new Person(20000M) { FirstName = "Charlie",LastName = "Cox", DateOfBirth = new DateTime(1984, 5, 4), Children = new HashSet { new Person(0M) { FirstName = "Sally", LastName = "Cox", DateOfBirth = new DateTime(2000, 7, 12) } } } }; //新建文件流 //文件保存的位置 string filePath = @"E:\xml.xml"; using (FileStream stream = new FileStream(filePath,FileMode.OpenOrCreate)) { //新建序列化对象 XmlSerializer xs = new XmlSerializer(typeof(List)); //序列号集合数据到文件中 xs.Serialize(stream, people); } //显示序列化后的内容 Console.WriteLine(File.ReadAllText(filePath)); //wait Console.ReadKey(); } } } 4.4实例:XML反序列化 using System; using System.IO; using System.Collections.Generic; using System.Xml.Serialization; namespace ConsoleApp6 { //测试用的类型 public class Person { Person() { } public Person(decimal initialSalary) { Salary = initialSalary; } public string FirstName { get; set; } public string LastName { get; set; } public DateTime DateOfBirth { get; set; } public HashSet Children { get; set; } protected decimal Salary { get; set; } } class Program { static void Main(string[] args) { //文件保存的位置 string filePath = @"E:\xml.xml"; using (FileStream xmlLoad = new FileStream(filePath,FileMode.OpenOrCreate)) { //序列化工具类 XmlSerializer xs = new XmlSerializer(typeof(List)); //执行反序列化操作 var loadedPeople = (List)xs.Deserialize(xmlLoad); //输出数据内容 foreach (var item in loadedPeople) { Console.WriteLine("{0} has {1} children.", item.LastName, item.Children.Count); } } //wait Console.ReadKey(); } } } 4.5实例:自定义XML元素的名称/将成员转为XML特性/自定义XML命名空间 using System; using System.IO; using System.Collections.Generic; using System.Xml.Serialization; namespace ConsoleApp6 { /// /// 测试使用的类型 /// [Serializable] [XmlRoot("PandaRoot", Namespace = "panda666.com")] public class Student { public int Id { get; set; } [XmlElement("PandaElement", Namespace = "panda666.com")] public string Name { get; set; } [XmlAttribute("PandaAttribute", Namespace = "panda666.com")] public int Age; } class Program { static void Main(string[] args) { //新建类型实例 Student student = new Student() { Id = 666, Name = "Panda", Age = 666666 }; //执行序列化 //创建文件流 string filePath = @"E:\xml.xml"; using (FileStream fileStream = new FileStream(filePath, FileMode.OpenOrCreate)) { //创建XML序列化对象 XmlSerializer xmlSerializer = new XmlSerializer(typeof(Student)); //执行序列化 xmlSerializer.Serialize(fileStream, student); } //执行反序列化 //创建文件流 using (FileStream fileStream1 = new FileStream(filePath, FileMode.Open)) { //创建XML序列化对象 XmlSerializer xmlSerializer = new XmlSerializer(typeof(Student)); //执行反序列化 Student data = (Student)xmlSerializer.Deserialize(fileStream1); //输出数据 Console.WriteLine($"{data.Id},{data.Name},{data.Age}"); } //wait Console.ReadKey(); } } } 五、二进制序列化 5.1使用方法

在需要支持序列化的类型上使用[Serializable]特性

[Serializable]

然后引入命名空间

using System.Runtime.Serialization.Formatters.Binary;

然后使用BinaryFormatter类型

BinaryFormatter binaryFormatter = new BinaryFormatter();

标记无需序列化的字段,使用[NonSerialized]特性修饰字段即可

[NonSerialized]

注意:BinaryFormatter类型在.NET 5中已经被标记为废弃,考虑使用JsonSerializer或XmlSerializer代替BinaryFormatter。

5.2实例:二进制序列化 using System; using System.IO; using System.Runtime.Serialization.Formatters.Binary; namespace ConsoleApp1 { /// /// 测试使用的类型 /// [Serializable] public class Student { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } } class Program { static void Main(string[] args) { //新建类型实例 Student student = new Student() { Id = 666, Name = "Panda", Age = 666666 }; //新建文件流 string filePath = @"E:\新建文本文档.txt"; using (FileStream fileStream = new FileStream(filePath, FileMode.OpenOrCreate)) { //新建二进制序列化对象 BinaryFormatter binaryFormatter = new BinaryFormatter(); //进行序列化 binaryFormatter.Serialize(fileStream, student); } //wait Console.WriteLine("Success"); Console.ReadKey(); } } } 5.3实例:二进制反序列化 using System; using System.IO; using System.Runtime.Serialization.Formatters.Binary; namespace ConsoleApp1 { /// /// 测试使用的类型 /// [Serializable] public class Student { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } } class Program { static void Main(string[] args) { //新建类型实例 Student student = new Student() { Id = 666, Name = "Panda", Age = 666666 }; //新建文件流 string filePath = @"E:\新建文本文档.txt"; using (FileStream fileStream = new FileStream(filePath, FileMode.OpenOrCreate)) { //新建二进制序列化对象 BinaryFormatter binaryFormatter = new BinaryFormatter(); //进行序列化 binaryFormatter.Serialize(fileStream, student); } //新建文件流 using(FileStream fileStream1 = new FileStream(filePath,FileMode.Open)) { //新建二进制序列化对象 BinaryFormatter binaryFormatter = new BinaryFormatter(); //进行反序列化 Student student1 = (Student)binaryFormatter.Deserialize(fileStream1); //输出反序列化的内容 Console.WriteLine($"{student1.Id},{student1.Name},{student1.Age}"); } //wait Console.WriteLine("Success"); Console.ReadKey(); } } } 5.4实例:标记无需序列化 using System; using System.IO; using System.Runtime.Serialization.Formatters.Binary; namespace ConsoleApp1 { /// /// 测试使用的类型 /// [Serializable] public class Student { public int Id { get; set; } public string Name { get; set; } [NonSerialized] public int Age; } class Program { static void Main(string[] args) { //新建类型实例 Student student = new Student() { Id = 666, Name = "Panda", Age = 666666 }; //新建文件流 string filePath = @"E:\新建文本文档.txt"; using (FileStream fileStream = new FileStream(filePath, FileMode.OpenOrCreate)) { //新建二进制序列化对象 BinaryFormatter binaryFormatter = new BinaryFormatter(); //进行序列化 binaryFormatter.Serialize(fileStream, student); } //新建文件流 using (FileStream fileStream1 = new FileStream(filePath, FileMode.Open)) { //新建二进制序列化对象 BinaryFormatter binaryFormatter = new BinaryFormatter(); //进行反序列化 Student student1 = (Student)binaryFormatter.Deserialize(fileStream1); //输出反序列化的内容 Console.WriteLine($"{student1.Id},{student1.Name},{student1.Age}"); } //wait Console.WriteLine("Success"); Console.ReadKey(); } } } 六、数据协定类型序列化 6.1数据协定说明

数据协定方式进行序列化和反序列化的优点:

不同的类型之间可以进行序列化和反序列化操作。 实现跨网络、跨平台、跨应用进行数据通信。 6.2使用方法 6.2.1基本使用

引入命名空间

using System.Runtime.Serialization;

直接使用DataContractSerializer类型进行序列化操作即可。

DataContractSerializer

注意:DataContractSerializer类型底层使用XML格式数据。如果需要在底层使用JSON格式数据,需要使用DataContractJsonSerializer。

DataContractJsonSerializer

DataContractJsonSerializer所在命名空间。

using System.Runtime.Serialization.Json; 6.2.2统一数据格式

所在命名空间

using System.Runtime.Serialization;

在需要序列化的类型上使用特性

[DataContract(Name = "PandaItem", Namespace = "panda666.com")]

在需要序列化的类型的成员上使用特性

[DataMember(Name = "PandaName")]

在不需要序列化的成员上使用特性

[IgnoreDataMember]

如需指定成员序列化的顺序,可以使用特性的Order成员

[DataMember(Name = "PandaId",Order = 1)] 6.2.3保留引用实例

对于多个数据重复引用,可以使用保留引用实例来减少数据的生成量。 注意:仅在底层是XML序列化中有效。

//新建序列化配置对象 DataContractSerializerSettings settings = new DataContractSerializerSettings(); //开启保留引用实例 settings.PreserveObjectReferences = true; //新建序列化对 DataContractSerializer dataContractSerializer = new DataContractSerializer(typeof(PandaClass), settings); 6.3实例:序列化数据 using System; using System.IO; using System.Runtime.Serialization; namespace ConsoleApp1 { /// /// 测试使用的类型 /// [Serializable] public class Student { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } } class Program { static void Main(string[] args) { //新建类型实例 Student student = new Student() { Id = 666, Name = "Panda", Age = 666666 }; //序列化数据 //新建文件流 string filePath = @"E:\新建文本文档.txt"; using(FileStream fileStream = new FileStream(filePath,FileMode.OpenOrCreate)) { //新建序列化对象 DataContractSerializer dataContractSerializer = new DataContractSerializer(typeof(Student)); //进行序列化 dataContractSerializer.WriteObject(fileStream, student); } //wait Console.WriteLine("Success"); Console.ReadKey(); } } } 6.4实例:反序列化数据 using System; using System.IO; using System.Runtime.Serialization; namespace ConsoleApp1 { /// /// 测试使用的类型 /// [Serializable] public class Student { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } } class Program { static void Main(string[] args) { //新建类型实例 Student student = new Student() { Id = 666, Name = "Panda", Age = 666666 }; //序列化数据 //新建文件流 string filePath = @"E:\新建文本文档.txt"; using(FileStream fileStream = new FileStream(filePath,FileMode.OpenOrCreate)) { //新建序列化对象 DataContractSerializer dataContractSerializer = new DataContractSerializer(typeof(Student)); //进行序列化 dataContractSerializer.WriteObject(fileStream, student); } //反序列化数据 //新建文件流 using (FileStream fileStream1 = new FileStream(filePath,FileMode.Open)) { //新建序列化对象 DataContractSerializer dataContractSerializer = new DataContractSerializer(typeof(Student)); //进行反序列化 Student student1 = (Student)dataContractSerializer.ReadObject(fileStream1); //输出反序列化的内容 Console.WriteLine($"{student1.Id},{student1.Name},{student1.Age}"); } //wait Console.WriteLine("Success"); Console.ReadKey(); } } } 6.5实例:跨类型进行序列化 using System; using System.IO; using System.Runtime.Serialization; namespace ConsoleApp1 { /// /// 测试使用的类型1 /// [DataContract(Name = "PandaItem", Namespace = "panda666.com")] public class PandaClass { [DataMember(Name = "PandaId")] public int Id { get; set; } [DataMember(Name = "PandaName")] public string Name { get; set; } [DataMember(Name = "PandaAge")] public int Age { get; set; } } /// /// 测试使用的类型2 /// [DataContract(Name = "PandaItem", Namespace = "panda666.com")] public class PandaClass2 { [DataMember(Name = "PandaId")] public int PandaId { get; set; } [DataMember(Name = "PandaName")] public string PandaName { get; set; } [DataMember(Name = "PandaAge")] public int PandaAge { get; set; } } class Program { static void Main(string[] args) { //新建类型实例 PandaClass panda = new PandaClass() { Id = 666, Name = "Panda", Age = 666666 }; //序列化数据 //新建文件流 string filePath = @"E:\新建文本文档.xml"; using (FileStream fileStream = new FileStream(filePath, FileMode.OpenOrCreate)) { //新建序列化对象 DataContractSerializer dataContractSerializer = new DataContractSerializer(typeof(PandaClass)); //进行序列化 dataContractSerializer.WriteObject(fileStream, panda); } //反序列化数据 using(FileStream fileStream1 = new FileStream(filePath,FileMode.Open)) { //新建序列化对象 DataContractSerializer dataContractSerializer = new DataContractSerializer(typeof(PandaClass2)); //进行反序列化 PandaClass2 data = (PandaClass2)dataContractSerializer.ReadObject(fileStream1); //输出数据 Console.WriteLine($"{data.PandaId},{data.PandaName},{data.PandaAge}"); } //wait Console.WriteLine("Success"); Console.ReadKey(); } } } 6.6实例:开启保留引用实例 using System; using System.IO; using System.Runtime.Serialization; namespace ConsoleApp1 { /// /// 测试使用的类型1 /// [DataContract(Name = "PandaItem", Namespace = "panda666.com")] public class PandaClass { [DataMember(Name = "PandaId")] public int Id { get; set; } [DataMember(Name = "PandaName")] public string Name { get; set; } [DataMember(Name = "PandaAge")] public int Age { get; set; } } /// /// 测试使用的类型2 /// [DataContract(Name = "PandaItem", Namespace = "panda666.com")] public class PandaClass2 { [DataMember(Name = "PandaId")] public int PandaId { get; set; } [DataMember(Name = "PandaName")] public string PandaName { get; set; } [DataMember(Name = "PandaAge")] public int PandaAge { get; set; } } class Program { static void Main(string[] args) { //新建类型实例 PandaClass panda = new PandaClass() { Id = 666, Name = "Panda", Age = 666666 }; //序列化数据 //新建文件流 string filePath = @"E:\新建文本文档.xml"; using (FileStream fileStream = new FileStream(filePath, FileMode.OpenOrCreate)) { //新建序列化配置对象 DataContractSerializerSettings settings = new DataContractSerializerSettings(); //开启保留引用实例 settings.PreserveObjectReferences = true; //新建序列化对象 DataContractSerializer dataContractSerializer = new DataContractSerializer(typeof(PandaClass), settings); //进行序列化 dataContractSerializer.WriteObject(fileStream, panda); } //反序列化数据 using (FileStream fileStream1 = new FileStream(filePath, FileMode.Open)) { //新建序列化对象 DataContractSerializer dataContractSerializer = new DataContractSerializer(typeof(PandaClass2)); //进行反序列化 PandaClass2 data = (PandaClass2)dataContractSerializer.ReadObject(fileStream1); //输出数据 Console.WriteLine($"{data.PandaId},{data.PandaName},{data.PandaAge}"); } //wait Console.WriteLine("Success"); Console.ReadKey(); } } } 6.7实例:跨类型进行序列化(底层JSON) using System; using System.IO; using System.Runtime.Serialization; using System.Runtime.Serialization.Json; namespace ConsoleApp1 { /// /// 测试使用的类型1 /// [DataContract(Name = "PandaItem")] public class PandaClass { [DataMember(Name = "PandaId")] public int Id { get; set; } [DataMember(Name = "PandaName")] public string Name { get; set; } [DataMember(Name = "PandaAge")] public int Age { get; set; } } /// /// 测试使用的类型2 /// [DataContract(Name = "PandaItem")] public class PandaClass2 { [DataMember(Name = "PandaId")] public int PandaId { get; set; } [DataMember(Name = "PandaName")] public string PandaName { get; set; } [DataMember(Name = "PandaAge")] public int PandaAge { get; set; } } class Program { static void Main(string[] args) { //新建类型实例 PandaClass panda = new PandaClass() { Id = 666, Name = "Panda", Age = 666666 }; //序列化数据 //新建文件流 string filePath = @"E:\新建文本文档.json"; using (FileStream fileStream = new FileStream(filePath, FileMode.OpenOrCreate)) { //新建序列化对象 DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(typeof(PandaClass)); //进行序列化 dataContractJsonSerializer.WriteObject(fileStream, panda); } //反序列化数据 using (FileStream fileStream1 = new FileStream(filePath, FileMode.Open)) { //新建序列化对象 DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(typeof(PandaClass2)); //进行反序列化 PandaClass2 data = (PandaClass2)dataContractJsonSerializer.ReadObject(fileStream1); //输出数据 Console.WriteLine($"{data.PandaId},{data.PandaName},{data.PandaAge}"); } //wait Console.WriteLine("Success"); Console.ReadKey(); } } }

本文来自博客园,作者:重庆熊猫,转载请注明原文链接:https://www.cnblogs.com/cqpanda/p/16153457.html



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3