当前位置: 首页 > news >正文

Newtonsoft.Json属性控制全攻略:从基础配置到高级技巧(含序列化/反序列化差异化处理)

Newtonsoft.Json属性控制全攻略:从基础配置到高级技巧

在.NET生态中,JSON数据的处理几乎成为每个开发者必备的技能。而Newtonsoft.Json(现称Json.NET)作为最受欢迎的JSON库之一,其灵活的属性控制能力让复杂的数据交互变得简单。本文将带你深入探索从基础配置到高级技巧的全方位属性控制方法。

1. 基础属性控制:入门必备

刚接触Newtonsoft.Json时,最基本的属性控制需求就是决定哪些属性参与序列化。JsonIgnoreJsonProperty这两个特性是最常用的工具。

public class UserProfile { [JsonIgnore] public string PasswordHash { get; set; } // 永远不会出现在JSON中 [JsonProperty("user_name")] public string Username { get; set; } // JSON中使用"user_name"作为键名 public DateTime CreatedAt { get; set; } // 保持原样 }

常见应用场景

  • 敏感数据过滤(如密码、密钥)
  • 统一命名风格(如将PascalCase转为snake_case)
  • 排除计算属性或临时字段

提示:JsonProperty不仅可以重命名属性,还能指定顺序(通过Order参数)和默认值(通过DefaultValueHandling)。

2. 条件序列化:动态控制属性输出

有时我们需要根据运行时条件决定是否包含某个属性。Newtonsoft.Json提供了几种方式实现条件序列化。

2.1 使用ShouldSerialize方法

public class Product { public string Name { get; set; } public decimal? DiscountPrice { get; set; } public bool ShouldSerializeDiscountPrice() { return DiscountPrice.HasValue && DiscountPrice > 0; } }

DiscountPrice为null或0时,它不会出现在输出的JSON中。

2.2 使用JsonProperty的Condition属性

public class Order { [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public string SpecialInstructions { get; set; } [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public DateTime? EstimatedDeliveryDate { get; set; } }

对比选择

方法适用场景优点缺点
ShouldSerialize复杂条件逻辑灵活性高需要额外方法
Property配置简单条件声明式,简洁条件有限

3. 序列化与反序列化差异化处理

实际开发中经常遇到这样的需求:某个属性在序列化时需要忽略,但在反序列化时需要保留。Newtonsoft.Json通过组合使用特性可以实现这种差异化处理。

public class SecureData { [JsonIgnore] public string ApiKey { get; set; } [JsonProperty("api_key")] private string ApiKeyForDeserialization { set => ApiKey = value; } }

工作原理

  1. 公共的ApiKey属性被标记为[JsonIgnore],序列化时会被忽略
  2. 私有的ApiKeyForDeserialization属性通过[JsonProperty]指定了JSON中的字段名
  3. 反序列化时,Newtonsoft.Json会找到匹配的api_key字段并赋值给私有属性
  4. 私有属性的setter将值传递给公共属性

进阶技巧:结合构造函数注入

public class Configuration { [JsonIgnore] public string Secret { get; } [JsonProperty("secret")] private string SecretForDeserialization { set => Secret = value; } [JsonConstructor] private Configuration(string secret) { Secret = secret; } }

4. 高级场景与性能优化

4.1 版本兼容性处理

处理API版本迭代时,经常需要兼容新旧数据结构:

public class UserV2 { [JsonProperty("name")] public string Username { get; set; } // 兼容旧版本的"user_name"字段 [JsonProperty("user_name", NullValueHandling = NullValueHandling.Ignore)] private string LegacyUsername { set => Username = value ?? Username; } }

4.2 自定义转换器

对于特殊类型的属性,可以创建自定义JsonConverter

public class UnixDateTimeConverter : JsonConverter { public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var date = (DateTime)value; writer.WriteValue((date - new DateTime(1970,1,1)).TotalSeconds); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { return new DateTime(1970,1,1).AddSeconds((long)reader.Value); } public override bool CanConvert(Type objectType) => objectType == typeof(DateTime); } public class Event { [JsonConverter(typeof(UnixDateTimeConverter))] public DateTime Timestamp { get; set; } }

4.3 性能优化技巧

  1. 缓存JsonSerializerSettings

    private static readonly JsonSerializerSettings Settings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, Converters = { new UnixDateTimeConverter() } }; // 复用Settings实例 var json = JsonConvert.SerializeObject(obj, Settings);
  2. 使用ContractResolver预编译

    var resolver = new DefaultContractResolver { NamingStrategy = new SnakeCaseNamingStrategy() }; var settings = new JsonSerializerSettings { ContractResolver = resolver };
  3. 避免频繁创建JObject/JArray

    // 不好 for(var i=0; i<100; i++) { var obj = JObject.Parse(json); // ... } // 好 var template = JObject.Parse(json); for(var i=0; i<100; i++) { var obj = (JObject)template.DeepClone(); // ... }

5. 实战案例:电商系统中的应用

假设我们正在开发一个电商系统,看看如何应用这些技巧处理复杂场景。

5.1 产品信息展示

public class Product { public int Id { get; set; } [JsonProperty("name")] public string ProductName { get; set; } [JsonIgnore] public decimal CostPrice { get; set; } public decimal SellingPrice { get; set; } [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public Discount CurrentDiscount { get; set; } public bool ShouldSerializeCurrentDiscount() => CurrentDiscount != null && CurrentDiscount.ValidUntil > DateTime.Now; } public class Discount { public decimal Percentage { get; set; } public DateTime ValidUntil { get; set; } }

5.2 订单处理流程

public class Order { public string OrderNumber { get; set; } [JsonConverter(typeof(UnixDateTimeConverter))] public DateTime OrderDate { get; set; } [JsonProperty("items")] public List<OrderItem> Items { get; set; } [JsonIgnore] public decimal TotalAmount => Items.Sum(i => i.Price * i.Quantity); // 反序列化时计算 [JsonProperty("total")] private decimal TotalAmountForDeserialization { set; } } public class OrderItem { public int ProductId { get; set; } public int Quantity { get; set; } public decimal Price { get; set; } }

5.3 用户敏感数据处理

public class User { public int Id { get; set; } public string Username { get; set; } [JsonIgnore] public string PasswordHash { get; set; } [JsonProperty("password")] private string PasswordForDeserialization { set => PasswordHash = HashPassword(value); } [JsonProperty("payment_methods")] public List<PaymentMethod> PaymentMethods { get; set; } public bool ShouldSerializePaymentMethods() => PaymentMethods != null && PaymentMethods.Any(); private string HashPassword(string input) => /* 哈希实现 */; }

在实际项目中,我发现最常遇到的坑是循环引用问题。特别是在处理实体关系时,比如订单和用户之间的双向引用。解决方法是配置ReferenceLoopHandling

var settings = new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
http://www.jsqmd.com/news/514350/

相关文章:

  • 【环境配置】Pnpm高效安装与优化配置实战
  • 20252803 2025-2026-2 《网络攻防实践》第1周作业
  • Kotaemon功能体验:如何用RAG技术打造专属文档助手
  • 支付宝上发票抽奖,扫一扫更方便。我还中了个100元
  • 通过注册表修改实现Excel 2010多窗口独立显示的完整指南
  • 计算机毕业设计:Python基于用户与物品的图书智能推荐系统 Django框架 协同过滤推荐算法 可视化 书籍 数据分析 大数据 大模型(建议收藏)✅
  • 别再傻傻分不清了!用Postman实战对比WebAPI和WebService,看完这篇就够了
  • 避开这些坑!宝塔FTP远程连接常见问题排查手册(含cpolar配置)
  • 避坑指南:在STM32CubeMX生成的Keil工程中添加自定义文件时容易忽略的5个配置细节
  • DeOldify图像上色服务赋能历史文化教育:互动式教学课件制作
  • 【开题答辩全过程】以 基于Android的宠物领养系统的设计与实现为例,包含答辩的问题和答案
  • 避障算法新选择:MPC-CBF在MATLAB中的5个关键实现步骤
  • 抢先卡位:亚马逊“领导者效应”的心智复利
  • 2024新版电池包结构仿真核心课程-精炼筛选的仿真领域精华
  • 0欧姆电阻的11种关键工程用途与选型指南
  • 企业微信H5聊天功能接入实战:从签名获取到组件封装全流程
  • Qwen2.5-7B-Instruct显存管理教程:一键清理+溢出报错应对全流程
  • Java、C# 与 C++:三大编程语言特点及应用场景深度分析
  • Zynq7000 USB控制器驱动开发避坑指南:从dQH/dTD链表到中断处理的实战解析
  • 2026上海高品质网站建设公司推荐 适配国际化数字化建站需求
  • SpringBoot+Vue 家教管理系统管理平台源码【适合毕设/课设/学习】Java+MySQL
  • GPT-3实战:如何用Few-Shot Learning提升你的NLP任务效果(附代码示例)
  • 单片机课程设计实战:八路抢答器从原理到实现的完整指南
  • 新手避坑指南:用TMS320F28377D的EPWM模块驱动IGBT,死区时间到底怎么设?
  • Realistic Vision V5.1 虚拟摄影棚:JDK版本特性对比图解生成
  • 基于BP神经网络的“数据回归预测与概率密度估计下置信区间预测”的Matlab代码(BP-PDE...
  • 科哥镜像实测CAM++:说话人识别系统5分钟搭建与核心功能体验
  • 数据结构优化实战:提升Qwen3-ASR-0.6B推理服务的内存与效率管理
  • ESP32脉冲计数器进阶玩法:用PCNT模块实现高精度正交编码(附完整配置)
  • HTC 10内存扩容实战:刷LineageOS 19.1后如何用lin_os_swap_mod增加运存