在C#开发中,服务端或第三方接口通常以JSON文本形式传递数据,客户端必须将这些文本还原为内存中的强类型对象,这一过程就是JSON反序列化。与序列化关注如何把对象转为字符串不同,反序列化要解决类型匹配、字段映射、格式容错等问题。如果处理方式不当,轻则拿到空对象,重则抛出运行时异常导致程序中断。

使用System.Text.Json完成基础反序列化
从.NET Core 3.0开始,微软在基础类库中内置了System.Text.Json命名空间,它不依赖外部包,主打高性能和低内存分配。其核心类型是JsonSerializer,通过静态方法Deserialize可以把字符串或流转换为指定泛型类型的实例。该库默认采用严格匹配策略,即JSON属性名必须与C#类属性名完全一致,且区分大小写。
假设我们有一个表示用户的类,包含编号和姓名两个字段。当接口返回{"id":1,"name":"张三"}时,直接调用反序列化即可获得对象。如果JSON里写的是UserId而类里是id,默认配置下会无法赋值。此时可以通过在属性上标记JsonPropertyName特性来建立映射关系,这样即使前后端命名风格不同也能正确绑定。
下面展示一个最小可运行示例,演示如何读取JSON并转为实体。注意代码中使用了using System.Text.Json;引入命名空间,并且通过JsonSerializerOptions关闭了大小写敏感,以提升容错能力。
using System;
using System.Text.Json;
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
class Program
{
static void Main()
{
string json = "{"id":1,"name":"张三"}";
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
User user = JsonSerializer.Deserialize<User>(json, options);
Console.WriteLine($"编号:{user.Id},姓名:{user.Name}");
}
}
这种原生方式的优势在于无需额外安装组件,适合对体积和启动速度敏感的应用。但它的灵活性相对较弱,例如处理动态字段、多态对象时需要编写自定义转换器,学习曲线比第三方库略陡。在简单DTO映射场景中,它往往是首选方案。
借助Newtonsoft.Json应对复杂结构
Newtonsoft.Json(常称Json.NET)是早期.NET生态中使用最广泛的JSON框架,其最大特点是配置灵活、扩展性强。它通过JsonConvert.DeserializeObject方法提供反序列化入口,并支持大量特性如JsonIgnore、JsonProperty来控制字段行为。对于历史项目或需要兼容多种格式的老接口,它依然是稳妥选择。
当JSON中存在可选字段、不同命名风格或需要忽略空值时,Newtonsoft只需在类定义或调用处设置即可。例如接口可能返回user_name这种下划线风格,我们可以在属性上用[JsonProperty("user_name")]标注,库会自动完成映射。此外它内置了对JObject的支持,允许先解析为动态结构再按需取值,避免定义完整实体类。
以下代码演示了如何用Newtonsoft还原包含嵌套地址信息的对象,并展示忽略某些属性的做法。我们在项目中需先通过包管理器安装Newtonsoft.Json,然后在文件顶部引用using Newtonsoft.Json;。
using System;
using Newtonsoft.Json;
public class Address
{
public string City { get; set; }
}
public class Person
{
[JsonProperty("user_name")]
public string UserName { get; set; }
[JsonIgnore]
public int InternalId { get; set; }
public Address Home { get; set; }
}
class Test
{
static void Main()
{
string json = "{"user_name":"李四","Home":{"City":"北京"}}";
Person p = JsonConvert.DeserializeObject<Person>(json);
Console.WriteLine(p.UserName + "来自" + p.Home.City);
}
}
从该示例可见,Newtonsoft对非常规结构容忍度更高,且社区资料丰富。不过它基于反射的机制在超高并发场景下分配内存较多,若系统追求极致吞吐,应评估是否切换至原生库或采用Source Generator方案。
处理异常与日期格式等常见坑点
反序列化并非总能一帆风顺,网络抖动、字段缺失、类型不符都会引发异常。System.Text.Json在解析失败时抛出JsonException,而Newtonsoft通常抛JsonReaderException或JsonSerializationException。生产代码中应当用try-catch包裹反序列化调用,并记录原始字符串以便排查,而不是让异常直接中断请求管线。
另一个高频问题是日期格式。JSON标准并未规定日期写法,有的接口用2024-03-01,有的用时间戳,有的带时区偏移。原生库可通过JsonConverter自定义解析逻辑,Newtonsoft则能在JsonSerializerSettings里设置DateFormatString。若忽略这一层,默认反序列化可能把时间变成本地时区的错误值,导致业务计算偏差。
下面示例用System.Text.Json演示如何编写一个处理特定日期格式的转换器,并注册到选项中。这样当遇到yyyy/MM/dd这类非标准文本时,依然能正确还原为DateTime。
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
public class CustomDateConverter : JsonConverter<DateTime>
{
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return DateTime.ParseExact(reader.GetString(), "yyyy/MM/dd", null);
}
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString("yyyy/MM/dd"));
}
}
public class Order
{
public string Product { get; set; }
[JsonConverter(typeof(CustomDateConverter))]
public DateTime CreateDate { get; set; }
}
class Demo
{
static void Main()
{
string json = "{"Product":"键盘","CreateDate":"2024/03/01"}";
Order o = JsonSerializer.Deserialize<Order>(json);
Console.WriteLine(o.Product + "下单于" + o.CreateDate.ToShortDateString());
}
}
除了日期,数字类型不一致也是隐患。例如接口把ID写成字符串"1001"而模型定义为long,原生库会直接报错。此时要么调整模型为string,要么在转换器里做类型兼容。明确接口契约、在网关层做格式校验,能从源头减少这类反序列化故障。
C#JSON反序列化Newtonsoft修改时间:2026-08-18 07:34:31