Newtonsoft.Json属性控制全攻略从基础配置到高级技巧在.NET生态中JSON数据的处理几乎成为每个开发者必备的技能。而Newtonsoft.Json现称Json.NET作为最受欢迎的JSON库之一其灵活的属性控制能力让复杂的数据交互变得简单。本文将带你深入探索从基础配置到高级技巧的全方位属性控制方法。1. 基础属性控制入门必备刚接触Newtonsoft.Json时最基本的属性控制需求就是决定哪些属性参与序列化。JsonIgnore和JsonProperty这两个特性是最常用的工具。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; } }工作原理公共的ApiKey属性被标记为[JsonIgnore]序列化时会被忽略私有的ApiKeyForDeserialization属性通过[JsonProperty]指定了JSON中的字段名反序列化时Newtonsoft.Json会找到匹配的api_key字段并赋值给私有属性私有属性的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 自定义转换器对于特殊类型的属性可以创建自定义JsonConverterpublic 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 性能优化技巧缓存JsonSerializerSettingsprivate static readonly JsonSerializerSettings Settings new JsonSerializerSettings { NullValueHandling NullValueHandling.Ignore, Converters { new UnixDateTimeConverter() } }; // 复用Settings实例 var json JsonConvert.SerializeObject(obj, Settings);使用ContractResolver预编译var resolver new DefaultContractResolver { NamingStrategy new SnakeCaseNamingStrategy() }; var settings new JsonSerializerSettings { ContractResolver resolver };避免频繁创建JObject/JArray// 不好 for(var i0; i100; i) { var obj JObject.Parse(json); // ... } // 好 var template JObject.Parse(json); for(var i0; i100; 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 ListOrderItem 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 ListPaymentMethod PaymentMethods { get; set; } public bool ShouldSerializePaymentMethods() PaymentMethods ! null PaymentMethods.Any(); private string HashPassword(string input) /* 哈希实现 */; }在实际项目中我发现最常遇到的坑是循环引用问题。特别是在处理实体关系时比如订单和用户之间的双向引用。解决方法是配置ReferenceLoopHandlingvar settings new JsonSerializerSettings { ReferenceLoopHandling ReferenceLoopHandling.Ignore };
Newtonsoft.Json属性控制全攻略:从基础配置到高级技巧(含序列化/反序列化差异化处理)
Newtonsoft.Json属性控制全攻略从基础配置到高级技巧在.NET生态中JSON数据的处理几乎成为每个开发者必备的技能。而Newtonsoft.Json现称Json.NET作为最受欢迎的JSON库之一其灵活的属性控制能力让复杂的数据交互变得简单。本文将带你深入探索从基础配置到高级技巧的全方位属性控制方法。1. 基础属性控制入门必备刚接触Newtonsoft.Json时最基本的属性控制需求就是决定哪些属性参与序列化。JsonIgnore和JsonProperty这两个特性是最常用的工具。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; } }工作原理公共的ApiKey属性被标记为[JsonIgnore]序列化时会被忽略私有的ApiKeyForDeserialization属性通过[JsonProperty]指定了JSON中的字段名反序列化时Newtonsoft.Json会找到匹配的api_key字段并赋值给私有属性私有属性的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 自定义转换器对于特殊类型的属性可以创建自定义JsonConverterpublic 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 性能优化技巧缓存JsonSerializerSettingsprivate static readonly JsonSerializerSettings Settings new JsonSerializerSettings { NullValueHandling NullValueHandling.Ignore, Converters { new UnixDateTimeConverter() } }; // 复用Settings实例 var json JsonConvert.SerializeObject(obj, Settings);使用ContractResolver预编译var resolver new DefaultContractResolver { NamingStrategy new SnakeCaseNamingStrategy() }; var settings new JsonSerializerSettings { ContractResolver resolver };避免频繁创建JObject/JArray// 不好 for(var i0; i100; i) { var obj JObject.Parse(json); // ... } // 好 var template JObject.Parse(json); for(var i0; i100; 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 ListOrderItem 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 ListPaymentMethod PaymentMethods { get; set; } public bool ShouldSerializePaymentMethods() PaymentMethods ! null PaymentMethods.Any(); private string HashPassword(string input) /* 哈希实现 */; }在实际项目中我发现最常遇到的坑是循环引用问题。特别是在处理实体关系时比如订单和用户之间的双向引用。解决方法是配置ReferenceLoopHandlingvar settings new JsonSerializerSettings { ReferenceLoopHandling ReferenceLoopHandling.Ignore };