如何在反序列化时为指定属性的Json转换器动态传参?
动态向特性标记的Json转换器传递反序列化参数
需求:反序列化时向Json转换器传递动态参数,同时仅让该转换器对通过[JsonConverter]特性标记的属性生效,避免将参数永久绑定到目标类中。
现有代码的问题:直接在JsonSerializerSettings.Converters中添加带参数的转换器实例,会让转换器对所有匹配类型的属性生效,而非仅标记特性的属性;若在特性中硬编码参数,又无法动态修改参数值。
方法一:利用StreamingContext传递参数+特性校验
这种方法无需修改特性定义,通过序列化上下文传递动态参数,在转换器中校验当前属性是否带有目标特性,再使用参数处理逻辑。
1. 修改转换器逻辑
public class MyJsonConverter : JsonConverter { // 无参构造函数,供特性标记时调用 public MyJsonConverter() { } // 保留带参构造函数,兼容原有代码结构 public MyJsonConverter(string parameter) { } public override bool CanConvert(Type objectType) { // 返回false,避免全局匹配类型,仅处理特性标记的属性 return false; } public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { // 仅处理属性节点 if (reader.TokenType != JsonToken.PropertyName) return reader.Value; var propertyName = (string)reader.Value!; // 从上下文获取预存的参数 if (serializer.Context.Context is not Dictionary<string, object> parameters) return reader.Value; // 获取当前属性的反射信息,校验是否带有目标特性 var property = typeof(Contract).GetProperty(propertyName); if (property == null) return reader.Value; var converterAttr = property.GetCustomAttribute<JsonConverterAttribute>(); if (converterAttr?.ConverterType != typeof(MyJsonConverter)) return reader.Value; // 使用动态参数处理反序列化 var parameter = parameters["DynamicParam"] as string; reader.Read(); // 移动到属性值节点 var rawValue = reader.Value?.ToString(); return $"[{parameter}] processed: {rawValue}"; } public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { writer.WriteValue(value); } }
2. 反序列化时传递参数
string json = "{\"Property\": \"original_value\"}"; string dynamicParam = "runtime_param_123"; // 封装参数到上下文 var paramContainer = new Dictionary<string, object> { {"DynamicParam", dynamicParam} }; var settings = new JsonSerializerSettings { Converters = { new MyJsonConverter() }, Context = new StreamingContext(StreamingContextStates.All, paramContainer) }; var contract = JsonConvert.DeserializeObject<Contract>(json, settings);
方法二:自定义契约解析器注入带参转换器
通过自定义契约解析器,在解析属性时将特性指定的转换器类型替换为带动态参数的实例,既保留特性的筛选逻辑,又实现参数动态传递。
1. 自定义契约解析器
public class DynamicConverterResolver : DefaultContractResolver { private readonly string _converterParam; public DynamicConverterResolver(string converterParam) { _converterParam = converterParam; } protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) { var property = base.CreateProperty(member, memberSerialization); // 检查当前属性是否标记了目标转换器特性 var converterAttr = member.GetCustomAttribute<JsonConverterAttribute>(); if (converterAttr != null && converterAttr.ConverterType == typeof(MyJsonConverter)) { // 替换为带动态参数的转换器实例 property.Converter = new MyJsonConverter(_converterParam); // 移除原特性,避免重复处理 property.AttributeProvider = new ConverterAttributeRemover(property.AttributeProvider); } return property; } // 辅助类:移除属性上的JsonConverter特性 private class ConverterAttributeRemover : IAttributeProvider { private readonly IAttributeProvider _innerProvider; public ConverterAttributeRemover(IAttributeProvider innerProvider) { _innerProvider = innerProvider; } public bool GetAttributes(Type attributeType, bool inherit) { return attributeType != typeof(JsonConverterAttribute) && _innerProvider.GetAttributes(attributeType, inherit); } public object[] GetAttributes(bool inherit) { return _innerProvider.GetAttributes(inherit) .Where(attr => attr.GetType() != typeof(JsonConverterAttribute)) .ToArray(); } } }
2. 转换器保持原有带参逻辑
public class MyJsonConverter : JsonConverter { private readonly string _parameter; public MyJsonConverter(string parameter) { _parameter = parameter; } public override bool CanConvert(Type objectType) { // 匹配属性的目标类型,比如string return objectType == typeof(string); } public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { var rawValue = reader.ReadAsString(); return $"[{_parameter}] processed: {rawValue}"; } public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { writer.WriteValue(value); } }
3. 反序列化时使用自定义解析器
string json = "{\"Property\": \"original_value\"}"; string dynamicParam = "runtime_param_456"; var settings = new JsonSerializerSettings { ContractResolver = new DynamicConverterResolver(dynamicParam) }; var contract = JsonConvert.DeserializeObject<Contract>(json, settings);
两种方法对比
- 方法一:无需修改契约解析器,通过上下文传递参数,适合多参数或复杂参数场景,但需要在转换器中手动校验特性。
- 方法二:职责分离清晰,转换器专注业务逻辑,解析器负责筛选和注入实例,对转换器侵入性更小,适合参数单一的场景。
内容的提问来源于stack exchange,提问作者marcin_
相关产品推荐
相关产品推荐

