1. .NET对象转JSON的常见场景与需求
在.NET开发中,对象与JSON之间的转换是日常开发中最频繁的操作之一。无论是Web API的数据传输、配置文件存储,还是前后端数据交互,都需要将内存中的对象序列化为JSON字符串,或者将JSON字符串反序列化为对象实例。
最近在Stack Overflow的.NET标签下,关于JSON序列化的问题每周都会新增上百个。开发者最常遇到的痛点包括:
- 循环引用导致的堆栈溢出
- 日期时间格式不一致
- 属性命名风格不匹配
- 性能瓶颈
- 特殊类型(如DataTable)的序列化问题
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 主流序列化方案对比
2.1 System.Text.Json(官方推荐)
.NET Core 3.0开始引入的高性能方案:
csharp复制// 基本序列化
var options = new JsonSerializerOptions {
WriteIndented = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
string json = JsonSerializer.Serialize(obj, options);
// 反序列化
var obj = JsonSerializer.Deserialize<T>(json, options);
优势:
- 零依赖,内置于.NET运行时
- 性能比Newtonsoft.Json高30%-50%
- 支持异步序列化
- 更安全(默认禁用不安全特性)
局限:
- 功能相对精简
- 某些高级配置需要自定义转换器
2.2 Newtonsoft.Json(Json.NET)
第三方库的经典选择:
csharp复制// 安装NuGet包:Newtonsoft.Json
var settings = new JsonSerializerSettings {
Formatting = Formatting.Indented,
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
string json = JsonConvert.SerializeObject(obj, settings);
// 反序列化
var obj = JsonConvert.DeserializeObject<T>(json, settings);
独有特性:
- 更灵活的配置选项
- 支持LINQ to JSON
- 完善的类型转换系统
- 更好的错误处理
2.3 DataContractJsonSerializer
WCF时代的遗留方案:
csharp复制using (var stream = new MemoryStream()) {
var serializer = new DataContractJsonSerializer(typeof(T));
serializer.WriteObject(stream, obj);
string json = Encoding.UTF8.GetString(stream.ToArray());
}
适用场景:
- 需要与WCF服务交互
- 严格的契约式编程
- 需要与XML序列化保持一致性
3. 高级场景解决方案
3.1 处理循环引用
System.Text.Json方案:
csharp复制var options = new JsonSerializerOptions {
ReferenceHandler = ReferenceHandler.Preserve
};
Newtonsoft.Json方案:
csharp复制var settings = new JsonSerializerSettings {
PreserveReferencesHandling = PreserveReferencesHandling.Objects
};
3.2 自定义转换器
日期格式转换示例:
csharp复制public class DateTimeConverter : JsonConverter<DateTime>
{
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return DateTime.ParseExact(reader.GetString(), "yyyy-MM-dd", CultureInfo.InvariantCulture);
}
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString("yyyy-MM-dd"));
}
}
3.3 性能优化技巧
- 重用JsonSerializerOptions实例
- 对热路径代码使用源生成器
csharp复制[JsonSerializable(typeof(MyPoco))]
public partial class MyContext : JsonSerializerContext {}
// 使用生成的序列化器
JsonSerializer.Serialize(obj, MyContext.Default.MyPoco);
- 使用ArrayPool减少内存分配
- 对大型数据集使用流式API
4. 实战对比测试
我们对三种方案进行基准测试(10000次序列化):
| 方案 | 耗时(ms) | 内存分配(MB) |
|---|---|---|
| System.Text.Json | 120 | 45 |
| Newtonsoft.Json | 180 | 68 |
| DataContractJsonSerializer | 350 | 92 |
测试环境:.NET 6, i7-11800H, 32GB RAM
5. 选型建议
根据项目需求选择:
- 新项目:优先使用System.Text.Json
- 遗留系统:继续使用Newtonsoft.Json
- WCF集成:考虑DataContractJsonSerializer
- 极致性能:System.Text.Json + 源生成器
对于特殊需求:
- 需要最大灵活性 → Newtonsoft.Json
- 需要最小依赖 → System.Text.Json
- 需要XML/JSON双向转换 → DataContractJsonSerializer
6. 常见问题排查
Q: 序列化时属性丢失?
- 检查属性可见性(System.Text.Json默认只序列化public属性)
- 检查[JsonIgnore]特性
- 确认命名策略配置
Q: 反序列化时报类型转换错误?
- 检查JSON中的类型与实际类型是否匹配
- 考虑使用自定义转换器
- 对于多态类型,配置TypeNameHandling(仅Newtonsoft.Json支持)
Q: 性能突然下降?
- 检查是否频繁创建JsonSerializerOptions实例
- 考虑启用源生成器
- 对大对象使用流式处理
7. 扩展方案
对于特殊场景还可以考虑:
- Utf8Json:第三方高性能库
- Jil:StackExchange开发的快速序列化器
- MessagePack:二进制序列化方案
我个人在大型项目中更倾向于组合使用System.Text.Json作为默认方案,配合Newtonsoft.Json处理特殊场景。对于性能关键路径,源生成器可以带来2-3倍的性能提升。
