一篇读懂 C# 序列化与反序列化:原理、实现与实战应用

2025博客之星年度评选已开启 10w+人浏览 1.7k人参与

序列化和反序列化是 C# 开发中核心的数据处理技术,广泛应用于数据持久化、跨进程通信、网络传输等场景。本文将从核心概念主流实现方式实战案例最佳实践,全方位拆解 C# 序列化 / 反序列化技术,帮你彻底掌握其原理与应用。

一、核心概念:什么是序列化与反序列化?

1. 序列化(Serialization)

内存中的对象(如自定义类实例、集合、结构体等)转换为可存储 / 可传输的格式(如二进制、XML、JSON、字节流)的过程。核心目的:突破内存限制,实现对象的持久化(存文件 / 数据库)或跨平台 / 跨进程传输(网络通信、RPC 调用)。

2. 反序列化(Deserialization)

将序列化后的字节流 / 文本数据还原为内存中原始对象的过程。核心要求:反序列化时必须能访问对象的类型定义,否则无法还原(如缺少类定义会抛出异常)。

3. 核心价值

  • 数据持久化:将对象保存到文件、数据库,程序重启后可恢复;
  • 跨进程通信:进程间、客户端 - 服务器间传输对象(如 WebAPI 返回 JSON 对象);
  • 分布式系统:微服务间调用时传递复杂数据结构;
  • 缓存 / 状态管理:将对象存入 Redis 等缓存中间件。

二、C# 主流序列化方式:特性、实现与对比

C# 提供了多种序列化方案,适配不同场景(性能、可读性、跨平台),以下是最常用的 4 种:

1. 二进制序列化(Binary Serialization)

核心特点
  • 基于System.Runtime.Serialization.Formatters.Binary命名空间;
  • 将对象转换为紧凑的二进制字节流,体积小、速度快;
  • 仅限.NET 平台(不跨语言),适合.NET 进程间通信 / 本地持久化;
  • 需为序列化类标记[Serializable]特性,不支持无参构造函数的类(反序列化时会绕过构造函数)。
实现步骤

步骤 1:定义可序列化的类

using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

// 必须标记[Serializable],否则序列化失败
[Serializable]
public class User
{
    // 字段会被序列化(属性的自动字段也会)
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime CreateTime { get; set; }

    // 可选:标记[NonSerialized]排除不需要序列化的字段
    [NonSerialized]
    private string _password; // 密码不序列化
}

步骤 2:序列化(对象→二进制流)

/// <summary>
/// 二进制序列化对象到文件
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="obj">待序列化对象</param>
/// <param name="filePath">保存路径</param>
public static void BinarySerialize<T>(T obj, string filePath)
{
    if (obj == null) throw new ArgumentNullException(nameof(obj));
    
    using (FileStream fs = new FileStream(filePath, FileMode.Create))
    {
        BinaryFormatter formatter = new BinaryFormatter();
        formatter.Serialize(fs, obj); // 写入二进制流
    }
}

步骤 3:反序列化(二进制流→对象)

/// <summary>
/// 从文件反序列化二进制数据为对象
/// </summary>
/// <typeparam name="T">目标类型</typeparam>
/// <param name="filePath">文件路径</param>
/// <returns>还原后的对象</returns>
public static T BinaryDeserialize<T>(string filePath)
{
    if (!File.Exists(filePath)) throw new FileNotFoundException("文件不存在", filePath);
    
    using (FileStream fs = new FileStream(filePath, FileMode.Open))
    {
        BinaryFormatter formatter = new BinaryFormatter();
        return (T)formatter.Deserialize(fs); // 还原对象
    }
}

步骤 4:调用示例

// 序列化
var user = new User { Id = 1, Name = "张三", CreateTime = DateTime.Now };
BinarySerialize(user, "user.bin");

// 反序列化
var restoredUser = BinaryDeserialize<User>("user.bin");
Console.WriteLine($"反序列化结果:ID={restoredUser.Id},姓名={restoredUser.Name}");
注意事项
  • BinaryFormatter在.NET 5 + 中被标记为过时(安全风险:反序列化不可信数据可能导致注入攻击);
  • 仅适用于.NET 内部场景,不推荐跨平台 / 公网使用。

2. XML 序列化(XmlSerializer)

核心特点
  • 基于System.Xml.Serialization命名空间;
  • 将对象转换为人类可读的 XML 文本,跨平台 / 跨语言(如 Java 可解析);
  • 无需标记[Serializable],但要求类有无参构造函数
  • 可通过特性自定义 XML 结构(如节点名、忽略字段)。
实现步骤

步骤 1:定义类(无需标记 [Serializable])

using System.Xml.Serialization;

public class Product
{
    // 无参构造函数(必须)
    public Product() { }

    // 自定义XML节点名
    [XmlAttribute("product-id")] // 作为XML属性
    public int Id { get; set; }

    [XmlElement("产品名称")] // 作为XML元素
    public string Name { get; set; }

    public decimal Price { get; set; }

    // 忽略序列化
    [XmlIgnore]
    public string Remark { get; set; }
}

步骤 2:序列化 / 反序列化工具方法

/// <summary>
/// XML序列化对象到文件
/// </summary>
public static void XmlSerialize<T>(T obj, string filePath)
{
    if (obj == null) throw new ArgumentNullException(nameof(obj));
    
    using (FileStream fs = new FileStream(filePath, FileMode.Create))
    {
        XmlSerializer serializer = new XmlSerializer(typeof(T));
        serializer.Serialize(fs, obj);
    }
}

/// <summary>
/// 从文件反序列化XML为对象
/// </summary>
public static T XmlDeserialize<T>(string filePath)
{
    if (!File.Exists(filePath)) throw new FileNotFoundException("文件不存在", filePath);
    
    using (FileStream fs = new FileStream(filePath, FileMode.Open))
    {
        XmlSerializer serializer = new XmlSerializer(typeof(T));
        return (T)serializer.Deserialize(fs);
    }
}

步骤 3:调用示例

// 序列化
var product = new Product 
{ 
    Id = 1001, 
    Name = "笔记本电脑", 
    Price = 5999.99m, 
    Remark = "内部备注" // 会被忽略
};
XmlSerialize(product, "product.xml");

// 反序列化
var restoredProduct = XmlDeserialize<Product>("product.xml");
Console.WriteLine($"XML反序列化:ID={restoredProduct.Id},名称={restoredProduct.Name},价格={restoredProduct.Price}");

生成的 XML 文件内容

<?xml version="1.0"?>
<Product xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" product-id="1001">
  <产品名称>笔记本电脑</产品名称>
  <Price>5999.99</Price>
</Product>
适用场景
  • 配置文件存储(如自定义 XML 配置);
  • 跨语言系统间的数据交换(如.NET 与 Java 对接);
  • 需要可读性的持久化场景。

3. JSON 序列化(System.Text.Json/Newtonsoft.Json)

JSON 是当前最主流的序列化格式,C# 提供两种核心实现:

  • System.Text.Json:.NET Core 3.0 + 内置,高性能、轻量;
  • Newtonsoft.Json(Json.NET:第三方库,功能更丰富,兼容所有.NET 版本。
方式 1:System.Text.Json(推荐)

步骤 1:定义类(无特殊标记)

public class Order
{
    public long OrderId { get; set; }
    public string Customer { get; set; }
    public DateTime OrderTime { get; set; }
    public List<string> Items { get; set; } = new List<string>();
}

步骤 2:序列化 / 反序列化

using System.Text.Json;

// 配置序列化选项(可选:美化格式、忽略空值、日期格式等)
var options = new JsonSerializerOptions
{
    WriteIndented = true, // 美化输出
    IgnoreNullValues = true, // 忽略空值字段
    PropertyNameCaseInsensitive = true // 反序列化时忽略大小写
};

// 序列化:对象→JSON字符串
var order = new Order
{
    OrderId = 2025001,
    Customer = "李四",
    OrderTime = DateTime.Now,
    Items = new List<string> { "手机", "耳机" }
};
string jsonStr = JsonSerializer.Serialize(order, options);
File.WriteAllText("order.json", jsonStr);

// 反序列化:JSON字符串→对象
string jsonContent = File.ReadAllText("order.json");
var restoredOrder = JsonSerializer.Deserialize<Order>(jsonContent, options);

Console.WriteLine($"JSON反序列化:订单ID={restoredOrder.OrderId},客户={restoredOrder.Customer}");

生成的 JSON 内容

{
  "OrderId": 2025001,
  "Customer": "李四",
  "OrderTime": "2025-12-18T10:30:00.0000000+08:00",
  "Items": [
    "手机",
    "耳机"
  ]
}
方式 2:Newtonsoft.Json(Json.NET

需先安装 NuGet 包:Install-Package Newtonsoft.Json

using Newtonsoft.Json;

// 序列化
string jsonStr = JsonConvert.SerializeObject(order, Formatting.Indented);
File.WriteAllText("order.json", jsonStr);

// 反序列化
var restoredOrder = JsonConvert.DeserializeObject<Order>(jsonContent);
核心优势
  • 轻量、高效、跨平台;
  • 支持复杂类型(如动态对象、匿名类型);
  • 广泛用于 WebAPI、前后端交互、微服务通信。

4. 协议缓冲区(Protobuf)

核心特点
  • 谷歌开源的二进制序列化协议(Google.Protobuf);
  • 比 JSON/XML 更小、更快,跨语言(C#/Java/Go/Python 等);
  • 需定义.proto文件描述数据结构,适合高性能跨平台通信。
快速实现
  1. 安装 NuGet 包:Install-Package Google.Protobuf
  2. 定义.proto文件(如Person.proto):
syntax = "proto3";
message Person {
  int32 id = 1;
  string name = 2;
  string email = 3;
  repeated string hobbies = 4; // 列表
}
  1. 通过工具生成 C# 类,再进行序列化 / 反序列化(篇幅限制,详细步骤可参考 Protobuf 官方文档)。

主流序列化方式对比

序列化方式可读性性能跨平台 / 跨语言适用场景
二进制序列化.NET 内部进程通信、本地持久化
XML 序列化配置文件、跨语言数据交换
JSON 序列化WebAPI、前后端交互、微服务
Protobuf极高高性能跨平台通信、大数据传输

三、关键特性与进阶技巧

1. 控制序列化范围

  • 排除字段 / 属性
    • 二进制:[NonSerialized](字段);
    • XML:[XmlIgnore]
    • JSON:[JsonIgnore](System.Text.Json)/[JsonProperty(NullValueHandling = NullValueHandling.Ignore)](Newtonsoft)。
  • 只序列化特定属性:XML/JSON 可通过自定义契约实现(如DataContract)。

2. 版本兼容性

当类结构变更(如新增字段、重命名属性),反序列化旧数据时可能出错:

  • 二进制序列化:推荐使用[OptionalField]标记新增字段;
  • JSON/XML:设置忽略未知属性(如JsonSerializerOptions.IgnoreUnknownFields = true)。

3. 处理循环引用

对象间循环引用(如 A 包含 B,B 包含 A)会导致序列化失败:

  • JSON:启用循环引用处理
    // System.Text.Json
    var options = new JsonSerializerOptions { ReferenceHandler = ReferenceHandler.Preserve };
    // Newtonsoft.Json
    JsonConvert.SerializeObject(obj, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
    

4. 自定义序列化逻辑

通过实现接口自定义序列化规则:

  • 二进制:ISerializable
  • JSON:JsonConverter(System.Text.Json)/JsonConverter<T>(Newtonsoft);
  • XML:IXmlSerializable

示例(JSON 自定义日期格式):

public class CustomDateTimeConverter : JsonConverter<DateTime>
{
    private readonly string _format = "yyyy-MM-dd HH:mm:ss";

    public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        return DateTime.Parse(reader.GetString()!);
    }

    public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(value.ToString(_format));
    }
}

// 使用自定义转换器
var options = new JsonSerializerOptions
{
    Converters = { new CustomDateTimeConverter() },
    WriteIndented = true
};
string json = JsonSerializer.Serialize(order, options);

四、实战应用场景

1. 数据持久化

将对象保存到本地文件 / 数据库,程序重启后恢复状态:

// 保存用户配置
var config = new AppConfig { Theme = "Dark", FontSize = 14, AutoSave = true };
string configJson = JsonSerializer.Serialize(config);
File.WriteAllText("appconfig.json", configJson);

// 程序启动时加载配置
if (File.Exists("appconfig.json"))
{
    string json = File.ReadAllText("appconfig.json");
    var loadedConfig = JsonSerializer.Deserialize<AppConfig>(json);
    // 应用配置...
}

2. WebAPI 数据传输

ASP.NET Core WebAPI 默认使用 System.Text.Json 序列化 / 反序列化:

[ApiController]
[Route("api/[controller]")]
public class UserController : ControllerBase
{
    // 序列化:返回User对象自动转为JSON
    [HttpGet("{id}")]
    public IActionResult GetUser(int id)
    {
        var user = new User { Id = id, Name = "张三" };
        return Ok(user); // 自动序列化为JSON响应
    }

    // 反序列化:请求体JSON自动转为User对象
    [HttpPost]
    public IActionResult AddUser([FromBody] User user)
    {
        // 处理用户数据...
        return CreatedAtAction(nameof(GetUser), new { id = user.Id }, user);
    }
}

3. 分布式缓存(Redis)

将对象序列化后存入 Redis,提升读取性能:

using StackExchange.Redis;

// 连接Redis
var redis = ConnectionMultiplexer.Connect("localhost:6379");
var db = redis.GetDatabase();

// 序列化对象为JSON字符串,存入Redis
var product = new Product { Id = 1001, Name = "手机", Price = 2999 };
string json = JsonSerializer.Serialize(product);
db.StringSet("product:1001", json, TimeSpan.FromHours(1)); // 1小时过期

// 从Redis读取并反序列化
string cachedJson = db.StringGet("product:1001");
if (!string.IsNullOrEmpty(cachedJson))
{
    var cachedProduct = JsonSerializer.Deserialize<Product>(cachedJson);
}

4. 跨进程通信(IPC)

通过命名管道 / 共享内存传输序列化后的对象:

// 进程1:序列化对象并写入命名管道
using (var pipe = new NamedPipeServerStream("MyPipe"))
{
    pipe.WaitForConnection();
    var user = new User { Id = 1, Name = "张三" };
    string json = JsonSerializer.Serialize(user);
    byte[] data = Encoding.UTF8.GetBytes(json);
    pipe.Write(data, 0, data.Length);
}

// 进程2:读取管道数据并反序列化
using (var pipe = new NamedPipeClientStream("MyPipe"))
{
    pipe.Connect();
    byte[] buffer = new byte[1024];
    int bytesRead = pipe.Read(buffer, 0, buffer.Length);
    string json = Encoding.UTF8.GetString(buffer, 0, bytesRead);
    var user = JsonSerializer.Deserialize<User>(json);
}

五、安全与性能最佳实践

1. 安全注意事项

  • 避免反序列化不可信数据(如网络请求中的二进制 / XML 数据):BinaryFormatter存在严重安全风险,优先使用 JSON/Protobuf;
  • 验证反序列化后的对象:检查字段值是否合法(如 ID 是否为正数、字符串长度是否合规);
  • 限制反序列化类型:通过自定义序列化器限制可还原的类型,防止类型注入攻击。

2. 性能优化

  • 复用序列化器实例:XmlSerializer/JsonSerializer创建成本高,建议缓存(如静态变量);
  • 选择合适的序列化格式:高性能场景用 Protobuf / 二进制,跨平台用 JSON;
  • 忽略不必要的字段:减少序列化数据体积,提升传输 / 存储效率;
  • 异步序列化 / 反序列化:IO 密集型场景(如文件 / 网络)使用SerializeAsync/DeserializeAsync

3. 常见坑点

  • 反序列化时缺少无参构造函数:XML/JSON 序列化要求类有公共无参构造函数;
  • 循环引用未处理:导致栈溢出或序列化失败;
  • 版本不一致:类结构变更后反序列化旧数据出错,需预留兼容性字段;
  • 敏感数据序列化:密码、令牌等敏感信息需加密后再序列化,或直接忽略。

六、总结

C# 序列化 / 反序列化是处理对象数据的核心技术,选择合适的方式是关键:

  • 本地 /.NET 内部场景:二进制序列化(注意安全);
  • 需可读性 / 跨语言:XML(配置)、JSON(Web);
  • 高性能跨平台:Protobuf;
  • Web / 前后端交互:优先 System.Text.Json(.NET Core+)或 Newtonsoft.Json(兼容旧版本)。

掌握序列化的核心原理、自定义规则和最佳实践,能有效解决数据持久化、跨系统通信等开发中的核心问题,提升代码的可扩展性和兼容性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值