C# 序列化技术全面解析:原理、实现与应用场景

article/2025/8/7 5:56:15

在软件开发中,数据持久化和网络通信是两个至关重要的环节。想象一下,当我们需要将一个复杂的对象保存到文件中,或者通过网络发送到另一台计算机时,如何有效地表示这个对象?这就是序列化技术要解决的问题。序列化(Serialization)是将对象转换为可存储或传输的格式的过程,而反序列化(Deserialization)则是将这些数据重新转换为对象的过程。

C# 作为一门成熟的面向对象编程语言,提供了丰富多样的序列化解决方案。本文将全面探讨 C# 中的各种序列化技术,包括二进制序列化、XML 序列化、JSON 序列化以及数据契约序列化,分析它们的原理、实现方式、优缺点以及适用场景,并通过实际代码示例展示如何在项目中应用这些技术。

一、序列化基础概念

1.1 什么是序列化

序列化是指将对象的状态信息转换为可以存储或传输的形式的过程。在序列化过程中,对象将其当前状态(通常是其成员变量的值)写入到临时或持久性存储区。之后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。

1.2 为什么需要序列化

序列化技术主要解决以下几个问题:

  1. 数据持久化:将对象状态保存到文件或数据库中,以便后续重新加载

  2. 远程通信:在不同应用程序域或网络中的计算机之间传输对象

  3. 进程间通信:在不同进程之间传递复杂数据结构

  4. 缓存机制:将对象缓存到内存或分布式缓存中

1.3 C# 中的序列化分类

C# 提供了多种序列化方式,主要可以分为以下几类:

  1. 二进制序列化

  2. XML 序列化

  3. JSON 序列化

  4. 数据契约序列化

  5. 自定义序列化

每种方式都有其特点和适用场景,开发者需要根据具体需求选择合适的序列化方式。

二、二进制序列化

2.1 二进制序列化概述

二进制序列化是将对象转换为二进制格式的过程,这种格式通常非常紧凑且处理速度快。在 .NET Framework 中,可以使用 BinaryFormatter 类来实现二进制序列化。

2.2 实现二进制序列化

下面是一个完整的二进制序列化示例:

using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;[Serializable]
public class Person
{public string Name { get; set; }public int Age { get; set; }[NonSerialized]public string TemporaryData; // 这个字段不会被序列化
}public class BinarySerializationDemo
{public static void Demo(){Person person = new Person { Name = "张三", Age = 30, TemporaryData = "临时数据" };// 序列化byte[] serializedData;using (MemoryStream stream = new MemoryStream()){BinaryFormatter formatter = new BinaryFormatter();formatter.Serialize(stream, person);serializedData = stream.ToArray();}Console.WriteLine($"序列化后的字节数: {serializedData.Length}");// 反序列化using (MemoryStream stream = new MemoryStream(serializedData)){BinaryFormatter formatter = new BinaryFormatter();Person deserializedPerson = (Person)formatter.Deserialize(stream);Console.WriteLine($"姓名: {deserializedPerson.Name}");Console.WriteLine($"年龄: {deserializedPerson.Age}");Console.WriteLine($"临时数据: {deserializedPerson.TemporaryData ?? "null"}");}}
}

2.3 二进制序列化的特点

优点:

  1. 序列化后的数据非常紧凑,占用空间小

  2. 序列化和反序列化速度快

  3. 可以完整保留对象图和类型信息

缺点:

  1. 数据不可读,难以调试

  2. 平台依赖性较强

  3. 在 .NET Core/.NET 5+ 中被认为不安全,已不建议使用

2.4 安全注意事项

由于 BinaryFormatter 存在严重的安全风险,微软已从 .NET Core 开始不推荐使用它。攻击者可能利用它执行任意代码。如果确实需要使用二进制序列化,可以考虑以下替代方案:

  1. 使用 System.Text.Json 或 Newtonsoft.Json 进行 JSON 序列化

  2. 使用 XmlSerializer 进行 XML 序列化

  3. 实现自定义的二进制序列化

三、XML 序列化

3.1 XML 序列化概述

XML 序列化将对象的公共属性和字段转换为 XML 格式。与二进制序列化不同,XML 序列化不包含类型信息,只序列化公共属性和字段。

3.2 实现 XML 序列化

using System;
using System.IO;
using System.Xml.Serialization;[Serializable]
public class Product
{public int Id { get; set; }public string Name { get; set; }public decimal Price { get; set; }[XmlIgnore]public DateTime CreatedAt { get; set; } // 这个属性不会被序列化
}public class XmlSerializationDemo
{public static void Demo(){Product product = new Product { Id = 1001, Name = "笔记本电脑", Price = 5999.99m,CreatedAt = DateTime.Now};// 序列化XmlSerializer serializer = new XmlSerializer(typeof(Product));string xmlString;using (StringWriter writer = new StringWriter()){serializer.Serialize(writer, product);xmlString = writer.ToString();}Console.WriteLine("序列化的XML:");Console.WriteLine(xmlString);// 反序列化using (StringReader reader = new StringReader(xmlString)){Product deserializedProduct = (Product)serializer.Deserialize(reader);Console.WriteLine($"\n反序列化结果:");Console.WriteLine($"ID: {deserializedProduct.Id}");Console.WriteLine($"名称: {deserializedProduct.Name}");Console.WriteLine($"价格: {deserializedProduct.Price}");Console.WriteLine($"创建时间: {deserializedProduct.CreatedAt}");}}
}

3.3 XML 序列化的特点

优点:

  1. 生成的 XML 可读性强

  2. 跨平台兼容性好

  3. 可以通过 XSD 验证数据格式

  4. 支持通过属性精细控制序列化过程

缺点:

  1. 数据冗余多,文件体积较大

  2. 序列化和反序列化性能较低

  3. 只能序列化公共成员

3.4 XML 序列化高级控制

通过使用各种 XML 特性,可以精细控制序列化过程:

[XmlRoot("ProductItem")]
public class AdvancedProduct
{[XmlAttribute("productId")]public int Id { get; set; }[XmlElement("productName")]public string Name { get; set; }[XmlElement("productPrice")]public decimal Price { get; set; }[XmlElement("isAvailable")]public bool IsAvailable { get; set; }[XmlArray("Categories")][XmlArrayItem("Category")]public List<string> Categories { get; set; }
}

四、JSON 序列化

4.1 JSON 序列化概述

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,也易于机器解析和生成。在 Web 开发和 API 设计中,JSON 已成为事实上的标准。

C# 中有两种主要的 JSON 序列化实现:

  1. System.Text.Json (.NET Core 3.0 及以后版本内置)

  2. Newtonsoft.Json (流行的第三方库)

4.2 使用 System.Text.Json 实现 JSON 序列化

using System;
using System.Text.Json;
using System.Text.Json.Serialization;public class Order
{public int OrderId { get; set; }public string CustomerName { get; set; }[JsonPropertyName("items")]public List<OrderItem> OrderItems { get; set; }[JsonIgnore]public string InternalNote { get; set; }
}public class OrderItem
{public string ProductName { get; set; }public int Quantity { get; set; }public decimal UnitPrice { get; set; }
}public class SystemTextJsonDemo
{public static void Demo(){Order order = new Order{OrderId = 1001,CustomerName = "李四",InternalNote = "重要客户",OrderItems = new List<OrderItem>{new OrderItem { ProductName = "鼠标", Quantity = 2, UnitPrice = 89.50m },new OrderItem { ProductName = "键盘", Quantity = 1, UnitPrice = 199.00m }}};// 序列化选项var options = new JsonSerializerOptions{WriteIndented = true, // 美化输出PropertyNamingPolicy = JsonNamingPolicy.CamelCase // 驼峰命名};// 序列化string jsonString = JsonSerializer.Serialize(order, options);Console.WriteLine("序列化的JSON:");Console.WriteLine(jsonString);// 反序列化Order deserializedOrder = JsonSerializer.Deserialize<Order>(jsonString, options);Console.WriteLine($"\n反序列化结果 - 订单ID: {deserializedOrder.OrderId}");Console.WriteLine($"客户名称: {deserializedOrder.CustomerName}");Console.WriteLine($"订单项数: {deserializedOrder.OrderItems?.Count ?? 0}");}
}

4.3 使用 Newtonsoft.Json 实现 JSON 序列化

using System;
using Newtonsoft.Json;public class NewtonsoftJsonDemo
{public static void Demo(){var data = new{Name = "王五",Age = 35,IsActive = true,LastLogin = DateTime.Now,Scores = new[] { 90, 85, 95 }};// 序列化设置var settings = new JsonSerializerSettings{Formatting = Formatting.Indented,NullValueHandling = NullValueHandling.Ignore,DateFormatString = "yyyy-MM-dd HH:mm:ss"};// 序列化string json = JsonConvert.SerializeObject(data, settings);Console.WriteLine("使用Newtonsoft.Json序列化的JSON:");Console.WriteLine(json);// 反序列化var deserializedData = JsonConvert.DeserializeAnonymousType(json, data, settings);Console.WriteLine($"\n反序列化结果 - 姓名: {deserializedData.Name}");Console.WriteLine($"年龄: {deserializedData.Age}");}
}

4.4 JSON 序列化的特点

优点:

  1. 数据格式轻量,文件体积小

  2. 可读性较好

  3. 广泛支持于各种编程语言和平台

  4. 在 Web 开发中已成为标准

缺点:

  1. 相比二进制格式,仍然有一定冗余

  2. 处理某些复杂类型(如循环引用)需要额外配置

4.5 System.Text.Json vs Newtonsoft.Json

特性System.Text.JsonNewtonsoft.Json
性能更高较低
内存分配更少较多
功能丰富度基本功能非常丰富
内置支持.NET Core 3.0+需要安装NuGet包
异步序列化支持不支持
处理循环引用有限支持完善支持

对于新项目,建议优先使用 System.Text.Json,除非需要 Newtonsoft.Json 的某些特有功能。

五、数据契约序列化

5.1 数据契约序列化概述

数据契约序列化是 WCF (Windows Communication Foundation) 中使用的一种序列化机制,通过 DataContractSerializer 类实现。它比 XML 序列化更灵活,但需要显式标记要序列化的成员。

5.2 实现数据契约序列化

using System;
using System.IO;
using System.Runtime.Serialization;[DataContract]
public class Employee
{[DataMember(Name = "id")]public int EmployeeId { get; set; }[DataMember]public string Name { get; set; }[DataMember(Order = 3)]public string Department { get; set; }public string SecretCode { get; set; } // 不会被序列化
}public class DataContractSerializationDemo
{public static void Demo(){Employee emp = new Employee{EmployeeId = 1001,Name = "赵六",Department = "研发部",SecretCode = "ABC123"};// 序列化DataContractSerializer serializer = new DataContractSerializer(typeof(Employee));string xmlString;using (var stream = new MemoryStream()){serializer.WriteObject(stream, emp);stream.Position = 0;using (var reader = new StreamReader(stream)){xmlString = reader.ReadToEnd();}}Console.WriteLine("数据契约序列化的XML:");Console.WriteLine(xmlString);// 反序列化using (var stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(xmlString))){Employee deserializedEmp = (Employee)serializer.ReadObject(stream);Console.WriteLine($"\n反序列化结果 - ID: {deserializedEmp.EmployeeId}");Console.WriteLine($"姓名: {deserializedEmp.Name}");Console.WriteLine($"部门: {deserializedEmp.Department}");Console.WriteLine($"密码: {deserializedEmp.SecretCode ?? "null"}");}}
}

5.3 数据契约序列化的特点

优点:

  1. 对序列化过程有更精细的控制

  2. 支持版本控制,对数据变更更友好

  3. 可以处理复杂对象图和继承层次结构

  4. 性能优于 XML 序列化

缺点:

  1. 需要显式标记要序列化的成员

  2. 生成的 XML 不如 XmlSerializer 生成的那么简洁

  3. 主要用于 WCF 服务

六、序列化技术选型指南

在选择序列化技术时,应考虑以下因素:

  1. 性能需求:二进制 > JSON ≈ 数据契约 > XML

  2. 数据大小:二进制 < JSON < 数据契约 < XML

  3. 可读性:XML ≈ JSON > 数据契约 > 二进制

  4. 跨平台支持:JSON > XML > 数据契约 > 二进制

  5. 类型安全:二进制 > 数据契约 > XML ≈ JSON

  6. 安全考虑:JSON ≈ XML > 数据契约 > 二进制

推荐场景:

  • Web API/前后端通信:JSON (System.Text.Json 或 Newtonsoft.Json)

  • 配置文件:JSON 或 XML

  • 高性能本地存储:考虑自定义二进制格式或 Protocol Buffers

  • WCF 服务:数据契约序列化

  • 临时对象存储:二进制序列化(仅限可信环境)

七、高级主题与最佳实践

7.1 处理循环引用

循环引用是指对象之间相互引用形成的环。默认情况下,许多序列化器无法处理这种情况。

在 Newtonsoft.Json 中处理循环引用:

var settings = new JsonSerializerSettings
{PreserveReferencesHandling = PreserveReferencesHandling.Objects,ReferenceLoopHandling = ReferenceLoopHandling.Serialize
};
string json = JsonConvert.SerializeObject(obj, settings);

在 System.Text.Json 中处理循环引用:

var options = new JsonSerializerOptions
{ReferenceHandler = ReferenceHandler.Preserve
};
string json = JsonSerializer.Serialize(obj, options);

 

7.2 自定义序列化

对于需要特殊处理的类型,可以实现自定义序列化逻辑:

public class CustomObject : IJsonOnSerializing, IJsonOnSerialized, IJsonOnDeserializing, IJsonOnDeserialized
{public string Data { get; set; }void IJsonOnSerializing.OnSerializing(){Console.WriteLine("序列化前调用");}void IJsonOnSerialized.OnSerialized(){Console.WriteLine("序列化后调用");}void IJsonOnDeserializing.OnDeserializing(){Console.WriteLine("反序列化前调用");}void IJsonOnDeserialized.OnDeserialized(){Console.WriteLine("反序列化后调用");}
}

7.3 版本兼容性考虑

在设计可序列化类型时,应考虑未来可能的变更:

  1. 避免删除已序列化的字段,可以标记为废弃

  2. 新添加的字段应提供合理的默认值

  3. 考虑使用 [OptionalField] 特性标记可能不存在的字段

  4. 实现 ISerializable 接口进行自定义版本控制

7.4 性能优化建议

  1. 对于频繁序列化的类型,缓存序列化器实例

  2. 对于大型对象,考虑流式序列化

  3. 使用 ArrayPool<byte> 减少内存分配

  4. 在 ASP.NET Core 中,使用 System.Text.Json 源生成器

八、结论

C# 提供了丰富多样的序列化技术,每种技术都有其适用场景。在现代应用开发中,JSON 序列化已成为最常用的方式,特别是对于 Web API 和前后端通信。System.Text.Json 作为 .NET 平台的新标准,提供了高性能和低内存占用的优势,而 Newtonsoft.Json 则因其丰富的功能仍然在许多项目中使用。

对于需要更高性能的场景,可以考虑二进制序列化,但应注意其安全风险。XML 序列化在需要严格模式验证或与旧系统集成的场景中仍然有价值。数据契约序列化则是 WCF 服务开发的首选。

选择序列化技术时,开发者应综合考虑性能需求、数据大小、可读性要求、跨平台需求和安全性等因素。理解各种序列化技术的原理和特点,能够帮助我们在实际项目中做出更合理的技术选型,构建更健壮、高效的应用程序。

 


http://www.hkcw.cn/article/vQhXlDMTPh.shtml

相关文章

如何检查popover气泡组件样式?调试悬停元素CSS样式的解决方案

1. 问题 当我们要检查这种弹出层的CSS样式时&#xff0c;会发现特别棘手&#xff0c;因为鼠标移走就消失了。如果是display:none控制的&#xff0c;可能还能找到&#xff0c;如果是用js通过v-if控制的&#xff0c;就无法调试了。 2. 解决方案 使用 setTimeout debugger 就…

DDR5 ECC详细原理介绍与基于协议讲解

本文篇幅较长,涉及背景原理介绍方便大家理解其运作方式 以及 基于DDR5协议具体展开介绍。 背景原理介绍 上图参考:DDR 内存中的 ECC 写入操作时,On-die ECC的工作过程如下: SoC将需要写入到Memory中的数据发送给控制器控制器将需要写入的数据直接发送给DRAM芯片在DDR5 DR…

设计模式——外观设计模式(结构型)

摘要 本文介绍了外观设计模式&#xff0c;它是一种结构型设计模式&#xff0c;通过引入一个外观类来封装复杂子系统的调用细节&#xff0c;对外提供简单统一的接口。文中通过生活类比、关键角色介绍、使用场景分析以及结构说明等方面对这一模式进行了全面阐述&#xff0c;还涉…

计算机网络(5)——数据链路层

1.概述 数据链路层负责一套链路上从一个节点向另一个物理链路直接相连的相邻节点传输数据报。换言之&#xff0c;主要解决相邻节点间的可靠数据传输 节点(nodes)&#xff1a;路由器和主机 链路(links)&#xff1a;连接相邻节点的通信信道 2.数据链路层服务 2.1 组帧 组帧(fra…

深度优先搜索(DFS)邻接矩阵实现

代码&#xff1a; // 访问标记数组&#xff0c;需要提前初始化为false bool visited[MAX_VERTEX_NUM]; void DFS(AMGraph G, int v) { // 图G为邻接矩阵类型&#xff0c;v是当前访问的顶点// 步骤1&#xff1a;访问顶点vcout << v; // 输出顶点编号…

将手机网络经USB数据线和本地局域网共享给华为AP6050DN无线接入点

引言 由于最近装毕的新家所在的小区未能及时通宽带,于是家中各类无线设备如何上网就成了首要要解决的问题。 鉴于家中要联网的设备多、类型杂、支持频段也不一,总是开手机热点不是回事儿,于是就想着把手机网络引至华为AP6050DN无线接入点中,让家中所有的无线设备都能快速高…

接口安全SOAPOpenAPIRESTful分类特征导入项目联动检测

1 、 API 分类特征 SOAP - WSDL OpenApi - Swagger RESTful - /v1/api/ 2 、 API 常见漏洞 OWASP API Security TOP 10 2023 3 、 API 检测流程 接口发现&#xff0c;遵循分类&#xff0c;依赖语言&#xff0c; V1/V2 多版本等 Method &#xff1a;请求方法 攻击方…

Python基础:常量、变量、变量类型、表达式、注释、输入输入、运算符

引言 手把手带你快速上手Python 一、常量和表达式 在Python中运行下面的代码&#xff1a; print(1 2 - 3) print(1 2 * 3) print(1 2 / 3)​​​​ 注意: print 是一个 Python 内置的 函数, 这个稍后详细介绍.可以使用 - * / ( ) 等运算符进行算术运算. 先算乘除, 后算加…

归一化相关

归一化相关问题 归一化方式Batch NormalizationLayer NormalizationInstance NormalizationGroup NormalizationRMSNorm(Root Mean Square Layer Normalization):RMSNorm 和 LayerNorm区别?归一化方式 Batch Normalization 在每一层的输入进行归一化处理,使其在每个批次内…

进阶日记(一)—LLMs本地部署与运行(更新中)

本项目资料主要来源&#xff1a;【知识科普】【纯本地化搭建】【不本地也行】DeepSeek RAGFlow 构建个人知识库_哔哩哔哩_bilibili 目录 一、背景知识 二、Ollma安装 三、Docker安装 接上一篇&#xff08;非科班大模型工程师进阶日记&#xff08;〇&#xff09;&#xff…

【论文解读】Deformable DETR | Deformable Transformers for End-to-End Object Detection

论文地址&#xff1a;https://arxiv.org/pdf/2010.04159 代码地址&#xff1a;https://github.com/fundamentalvision/Deformable-DETR 摘要 DETR最近被提出&#xff0c;旨在消除物体检测中许多手工设计的组件的需求&#xff0c;同时展示出良好的性能。然而&#xff0c;由于T…

大语言模型的推理能力

2025年&#xff0c;各种会推理的AI模型如雨后春笋般涌现&#xff0c;比如ChatGPT o1/o3/o4、DeepSeek r1、Gemini 2 Flash Thinking、Claude 3.7 Sonnet (Extended Thinking)。 对于工程上一些问题比如复杂的自然语言转sql&#xff0c;我们可能忍受模型的得到正确答案需要更多…

PINN for PDE(偏微分方程)1 - 正向问题

PINN for PDE(偏微分方程)1 - 正向问题 目录 PINN for PDE(偏微分方程)1 - 正向问题一、什么是PINN的正问题二、求解的实际例子三、基于Pytorch实现的代码 - 分解3.1 引入库函数3.2 设置超参数3.3 设计随机种子&#xff0c;确保复现结果的一致性3.4 对于条件等式生成对应的训练…

Adobe LiveCycle ES、LiveCycle DS 与 BlazeDS 关系解析与比较

Adobe LiveCycle 系列产品是企业级解决方案的重要组成部分&#xff0c;但在命名和功能上常常造成混淆。 产品定义 Adobe LiveCycle ES (Enterprise Suite) LiveCycle ES是一个基于SOA的平台&#xff0c;部署在J2EE应用服务器上。它提供开发、部署、配置和执行服务的功能。基…

Redis最佳实践——性能优化技巧之监控与告警详解

Redis 在电商应用的性能优化技巧之监控与告警全面详解 一、监控体系构建 1. 核心监控指标矩阵 指标类别关键指标计算方式/说明健康阈值&#xff08;参考值&#xff09;内存相关used_memoryINFO Memory 获取不超过 maxmemory 的 80%mem_fragmentation_ratio内存碎片率 used_m…

使用 DeepSeek API 搭建智能体《无间》- 卓伊凡的完整指南 -优雅草卓伊凡

使用 DeepSeek API 搭建智能体《无间》- 卓伊凡的完整指南 -优雅草卓伊凡 作者&#xff1a;卓伊凡 前言&#xff1a;为什么选择 DeepSeek API&#xff0c;而非私有化部署&#xff1f; 在开始搭建智能体之前&#xff0c;我想先说明 为什么推荐使用 DeepSeek API&#xff0c;而…

lidar和imu的标定(三)平面约束的方法

看了一篇&#xff1a;基于平面特征的地面机器人雷达-惯性里程计外参标定方法&#xff1b; 它和GRIL-Calib不同之处&#xff0c;就是采用了平面优化和栅格优化。 栅格优化就不介绍了&#xff0c;感觉工程上不。 平面优化则很容易懂&#xff0c;就是标定出来了激光雷达到IMU之…

CppCon 2014 学习: C++ on Mars

主要介绍了如何在火星探测器的飞行软件中使用 C。&#xff1a; 介绍了火星探测器&#xff08;如 Sojourner, Spirit, Opportunity, Curiosity, Perseverance&#xff09;。强调其复杂性和自主性。 延迟的现实&#xff1a;地球与火星之间的通信时延 单程信号延迟为 4 到 22 分…

【MFC】初识MFC

目录 01 模态和非模态对话框 02 静态文本 static text 01 模态和非模态对话框 首先我们需要知道模态对话框和非模态对话框的区别&#xff1a; 模态对话框是一种阻塞时对话框&#xff0c;它会阻止用户与应用程序的其他部分进行交互&#xff0c;直到用户与该对话框进行交互并关…

C#数字图像处理(二)

文章目录 1.灰度直方图1.1 灰度直方图定义1.2 灰度直方图编程实例 2.线性点运算2.1线性点运算定义2.2 线性点运算编程实例 3.全等级直方图灰度拉伸3.1 灰度拉伸定义3.2 灰度拉伸编程实例 4.直方图均衡化4.1 直方图均衡化定义4.2 直方图均衡化编程实例 5.直方图匹配5.1 直方图匹…