如何在自定义JSON转换器中访问.NET类的自定义属性
在自定义JSON转换器中访问.NET类的自定义属性
要在你的StringSanitizingConverter中读取目标属性的自定义属性,我们可以分三步实现,同时兼顾灵活性和通用性:
1. 定义自定义标记属性
先创建一个可配置的自定义属性,用来标记需要特殊处理的字符串属性,还能通过参数控制修剪逻辑:
[AttributeUsage(AttributeTargets.Property)] public class StringSanitizeSettingsAttribute : Attribute { // 默认修剪首尾空格 public bool TrimLeading { get; set; } = true; public bool TrimTrailing { get; set; } = true; // 可选:合并中间多余空格 public bool CollapseExtraSpaces { get; set; } = false; }
2. 修改自定义转换器,添加属性读取逻辑
核心思路是:在反序列化时定位当前处理的属性,通过反射获取它的自定义属性,再根据配置处理字符串。下面的实现同时支持根对象和嵌套对象场景:
public class StringSanitizingConverter : JsonConverter { public override bool CanConvert(Type objectType) { return objectType == typeof(string); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) return null; string rawValue = reader.Value.ToString(); if (string.IsNullOrWhiteSpace(rawValue)) return rawValue; // 1. 获取当前属性的路径(如 "CandidateName" 或 "Address.Street") string propertyPath = reader.Path; string targetPropName = propertyPath.Split('.').Last(); // 2. 定位属性所属的父对象类型 Type parentType = GetParentObjectType(reader, serializer); if (parentType == null) return rawValue.Trim(); // 无上下文时默认修剪首尾 // 3. 通过反射读取自定义属性配置 PropertyInfo targetProp = parentType.GetProperty(targetPropName); var sanitizeConfig = targetProp?.GetCustomAttribute<StringSanitizeSettingsAttribute>(); // 4. 根据配置处理字符串 if (sanitizeConfig != null) { if (sanitizeConfig.TrimLeading) rawValue = rawValue.TrimStart(); if (sanitizeConfig.TrimTrailing) rawValue = rawValue.TrimEnd(); if (sanitizeConfig.CollapseExtraSpaces) rawValue = System.Text.RegularExpressions.Regex.Replace(rawValue, @"\s+", " "); } else { // 未标记自定义属性时的默认行为 rawValue = rawValue.Trim(); } return rawValue; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { writer.WriteValue(value?.ToString()); } // 辅助方法:获取当前属性所属的父对象类型 private Type GetParentObjectType(JsonReader reader, JsonSerializer serializer) { // 处理根对象场景:从序列化上下文获取类型 if (reader.Parent == null) return serializer.Context.Context as Type; // 处理嵌套对象场景:回溯JToken获取父对象类型 JToken currentToken = reader.CurrentToken; while (currentToken.Parent != null) { currentToken = currentToken.Parent; if (currentToken is JObject parentObj) { var objContract = serializer.ContractResolver.ResolveContract(parentObj.GetType()) as JsonObjectContract; return objContract?.UnderlyingType; } } return null; } }
3. 在实体类中使用自定义属性和转换器
现在可以在你的Candidate类中标记属性,指定不同的处理规则:
public class Candidate { // 标记需要合并多余空格的属性 [StringSanitizeSettings(CollapseExtraSpaces = true)] [JsonConverter(typeof(StringSanitizingConverter))] public string CandidateName { get; set; } // 使用默认配置(仅修剪首尾空格) [StringSanitizeSettings] [JsonConverter(typeof(StringSanitizingConverter))] public string Email { get; set; } }
反序列化配置示例
如果全局注册转换器(而非在每个属性上标记[JsonConverter]),记得传递根对象类型上下文,确保转换器能正确识别嵌套属性:
var jsonSettings = new JsonSerializerSettings { Converters = new List<JsonConverter> { new StringSanitizingConverter() }, // 传递根对象类型,帮助转换器定位属性所属类 Context = new StreamingContext(StreamingContextStates.All, typeof(Candidate)) }; // 测试反序列化 string json = "{\"CandidateName\": \" John Doe \", \"Email\": \" john@example.com \"}"; var candidate = JsonConvert.DeserializeObject<Candidate>(json, jsonSettings); // 结果:CandidateName = "John Doe",Email = "john@example.com"
内容的提问来源于stack exchange,提问作者dks
相关产品推荐
相关产品推荐

