C#教程

关注公众号 jb51net

关闭
首页 > 软件编程 > C#教程 > C# JSON序列化与反序列化

C# JSON序列化与反序列化的最佳实践

作者:加号3

在现代软件开发中,JSON已成为数据交换的事实标准,无论是与 Web API 通信、配置文件管理,还是微服务间的消息传递,JSON 都无处不在,C#作为一门强类型语言,提供了丰富而成熟的 JSON 处理能力,本文将系统性地介绍C#中JSON序列化与反序列化的核心概念

在现代软件开发中,JSON(JavaScript Object Notation)已成为数据交换的事实标准。无论是与 Web API 通信、配置文件管理,还是微服务间的消息传递,JSON 都无处不在。C# 作为一门强类型语言,提供了丰富而成熟的 JSON 处理能力。本文将系统性地介绍 C# 中 JSON 序列化与反序列化的核心概念、主流方案、设计哲学以及工程实践中的关键考量。

一、序列化与反序列化的本质

在深入技术细节之前,有必要先厘清这两个核心概念:

这一过程看似简单,实则涉及类型系统映射、引用关系处理、循环依赖检测、数据验证等复杂问题。理解这一点,有助于我们在遇到异常行为时快速定位根因。

二、C# 中的两大主流方案

.NET 生态中,JSON 处理经历了从第三方库到官方内置方案的演进,形成了当前双雄并立的格局。

1. Newtonsoft.Json(Json.NET)

作为 .NET 领域历史最悠久、功能最丰富的 JSON 库,Newtonsoft.Json 由 James Newton-King 开发,长期以来一直是行业标准。其特点包括:

在 .NET Core 3.0 之前,Newtonsoft.Json 几乎是每个项目的标配依赖。

2. System.Text.Json

随着 .NET Core 3.0 的发布,微软推出了官方内置的高性能 JSON 库 System.Text.Json。其设计目标非常明确:

然而,早期版本的 System.Text.Json 在功能丰富度上不及 Newtonsoft.Json。经过 .NET 5、6、7、8 的持续迭代,目前已覆盖绝大多数常见场景,但在处理高度动态化或遗留系统兼容时,仍可能需要借助 Newtonsoft.Json 的灵活性。

三、核心机制与配置哲学

无论选择哪种方案,理解其配置哲学都是高效使用的前提。

1. 命名策略(Naming Policy)

C# 遵循 PascalCase 命名规范(如 UserName),而 JSON 生态中更常见 camelCase(如 userName)或 snake_case(如 user_name)。序列化库通常提供全局或局部的命名策略配置,以确保两端命名风格的无缝映射。

2. 空值处理

对于可空属性,需要决定序列化时是否包含空值字段。包含空值会增加传输体积,但有助于保持结构完整性;忽略空值则能减少数据量,但可能导致接收方无法区分"未设置"和"设置为 null"。

3. 日期与时间处理

JSON 标准并未定义日期格式,实践中通常采用 ISO 8601 格式(如 2026-05-21T08:50:00Z)。处理时区、本地时间与 UTC 时间的转换,以及高精度时间戳的支持,都是配置中需要关注的要点。

4. 循环引用与对象图

当对象间存在双向引用(如父子节点互相引用)时,简单的序列化会导致无限递归。成熟的库提供两种解决路径:一是忽略循环引用(可能丢失数据),二是通过引用标识符(id、id、idref)保留对象图的完整性。

5. 多态类型处理

在面向对象设计中,基类引用指向派生类实例是常见模式。序列化时需要决定是否包含类型信息,以便反序列化时准确重建对象类型。这通常通过类型判别器(Discriminator)或全类型名称嵌入实现。

四、自定义行为与扩展点

实际项目中,自动映射往往无法满足所有需求。两种方案都提供了强大的扩展机制。

1. 自定义转换器(JsonConverter)

当标准映射规则不适用时(如特殊格式字符串、复杂枚举、加密字段),可以编写自定义转换器。转换器允许你完全控制特定类型的读写逻辑,实现业务层面的精确映射。

2. 属性注解(Attributes)

通过在模型属性上添加注解,可以局部覆盖全局配置。常见用途包括:

3. 契约解析器(Contract Resolver)

在 Newtonsoft.Json 中,契约解析器提供了更底层的控制,允许通过编程方式动态决定序列化行为,而无需修改模型类本身。这在无法注解第三方类或需要运行时动态策略时特别有用。

五、基于Newtonsoft.Json库代码实现

public class JsonUtils
{
    /// <summary>
    /// 将对象转换成Json文件
    /// </summary>
    /// <param name="obj">类对象参数</param>
    /// <param name="jsonFile">Json文件完整路径</param>
    /// <returns></returns>
    public static bool ToJsonFile(object obj, string jsonFile)
    {
        if (obj != null)
        {
            string json = JsonConvert.SerializeObject(obj);
            File.WriteAllText(jsonFile, json);
            return true;
        }
        return false;
    }

    /// <summary>
    /// 从Json文件反序列化
    /// </summary>
    /// <typeparam name="T">泛型类</typeparam>
    /// <param name="jsonFile">Json文件完整路径</param>
    /// <returns></returns>
    public static T? FromJsonFile<T>(string jsonFile)
    {
        if (File.Exists(jsonFile))
        {
            string json = File.ReadAllText(jsonFile);
            T? jsonObj = JsonConvert.DeserializeObject<T>(json);
            return jsonObj;
        }
        return default;
    }

    /// <summary>
    /// 将对象序列化Json字符串
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static string ToJson(object? obj)
    {
        if (obj != null)
        {
            string json = JsonConvert.SerializeObject(obj);
            return json;
        }
        return string.Empty;
    }

    /// <summary>
    /// 将Json字符串反序列化为对象
    /// </summary>
    /// <typeparam name="T">泛型类</typeparam>
    /// <param name="json">Json字符串</param>
    /// <returns></returns>
    public static T? FromJson<T>(string? json)
    {
        if (!string.IsNullOrEmpty(json))
        {
            T? jsonObj = JsonConvert.DeserializeObject<T>(json);
            return jsonObj;
        }
        return default;
    }
}

六、性能考量与选型建议

性能差异是两种方案最显著的区别之一。System.Text.Json 在设计上充分利用了现代 .NET 的内存管理优化,特别适合高吞吐量场景,如微服务网关、高频 API 接口、实时数据流处理。
然而,性能并非唯一指标。在以下场景,Newtonsoft.Json 仍是更稳妥的选择:

对于新项目,建议优先评估 System.Text.Json 是否满足需求;若功能缺口不大,其原生集成和性能优势值得采用。若遇到边界情况,两者也可以共存——.NET 允许在不同场景下分别使用不同的序列化器。

七、反序列化的安全与健壮性

反序列化是不可信数据进入系统的关键入口,必须谨慎处理。

1. 类型安全

反序列化到强类型对象是最安全的做法,因为类型系统会自然过滤不兼容数据。若必须使用弱类型(如 JsonElement 或 JToken),务必在访问时进行显式类型检查和转换。

2. 深度与大小限制

恶意构造的 JSON(如深度嵌套对象、超大字符串)可能导致栈溢出或内存耗尽。生产环境应配置最大深度、字符串长度和缓冲区大小限制。

3. 数字范围检查

JSON 数字没有显式类型边界,反序列化到 C# 数值类型时可能发生溢出。应在模型中使用合适范围的类型,或在反序列化后手动验证。

八、总结

C# 的 JSON 处理能力经过十余年发展,已形成成熟且多元的解决方案。System.Text.Json 代表了官方的高性能、现代化方向,而 Newtonsoft.Json 凭借其无与伦比的灵活性仍在复杂场景中占据重要地位。

作为开发者,理解两者的设计哲学差异,根据项目实际需求做出选型,并在序列化契约设计中兼顾性能、安全与可维护性,是构建健壮系统的关键。JSON 序列化看似只是"对象转字符串"的简单操作,但其背后涉及的类型系统、内存管理和安全考量,正是工程化思维的最佳体现。

以上就是C# JSON序列化与反序列化的最佳实践的详细内容,更多关于C# JSON序列化与反序列化的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文