You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在反序列化时为指定属性的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_

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 18:50:23