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

如何基于JSON的method字段实现C#泛型JSON转换器?

不用写几百个case!优雅实现基于method字段的泛型JSON转换

你完全没必要靠庞大的switch语句来处理几百种模型,这不仅维护起来像噩梦,还违反了开闭原则(新增模型还要修改转换逻辑)。下面给你两种实用的解决方案,尤其适合大量模型的场景:

方案一:类型映射字典 + 反射(最推荐)

核心思路是提前建立method字符串到对应模型类型的映射,然后通过反射动态调用反序列化方法,完全不用写switch。

步骤1:统一模型的基类/接口(可选但推荐)

先给所有模型定义一个共同的接口,方便后续统一处理:

public interface IRequestModel { }

public class Model : IRequestModel 
{ 
    public string Key { get; set; } 
}

public class OtherModel : IRequestModel 
{ 
    public string Foo { get; set; } 
}

步骤2:定义泛型容器和结果类

和你的原型保持一致,加上泛型约束:

public class JsonData<T> where T : IRequestModel
{
    public string Method { get; set; } // 对应JSON中的method字段
    public T Payload { get; set; }
}

public class LogInfoRequestResult<T> : IResult where T : IRequestModel
{
    public JsonData<T> Raw { get; set; }
    // 实现IResult的其他成员...
}

步骤3:实现动态转换逻辑

这里关键是用类型字典替代switch,并且用JObject解析JSON(比Regex可靠100倍,不会因为JSON格式变化出错):

public class JsonPayloadConverter
{
    // 静态字典:method名称 → 模型类型
    private static readonly Dictionary<string, Type> _modelTypeMap;

    static JsonPayloadConverter()
    {
        _modelTypeMap = new Dictionary<string, Type>(StringComparer.OrdinalIgnoreCase);
        
        // 【手动注册】适合少量模型,或者用下面的【自动注册】适合几百个模型
        _modelTypeMap.Add("Model", typeof(Model));
        _modelTypeMap.Add("OtherModel", typeof(OtherModel));

        // 【自动注册】扫描程序集中所有实现IRequestModel的类型,无需手动添加
        // var assembly = Assembly.GetExecutingAssembly();
        // var modelTypes = assembly.GetTypes()
        //     .Where(t => typeof(IRequestModel).IsAssignableFrom(t) 
        //                 && !t.IsInterface 
        //                 && !t.IsAbstract);
        // foreach (var type in modelTypes)
        // {
        //     // 默认用类名作为method值,也可以自定义Attribute指定别名
        //     _modelTypeMap.Add(type.Name, type);
        // }
    }

    public IResult ParseJson(string json)
    {
        // 先解析JSON,安全提取method字段
        var jObject = JObject.Parse(json);
        if (!jObject.TryGetValue("method", out var methodToken) || methodToken.Type != JTokenType.String)
        {
            throw new InvalidOperationException("JSON格式错误:缺少或无效的'method'字段");
        }

        var methodName = methodToken.Value<string>();
        if (!_modelTypeMap.TryGetValue(methodName, out var modelType))
        {
            throw new NotSupportedException($"不支持的method类型:{methodName}");
        }

        // 动态创建泛型的JsonData<T>并反序列化
        var jsonDataGenericType = typeof(JsonData<>).MakeGenericType(modelType);
        var rawData = JsonConvert.DeserializeObject(json, jsonDataGenericType);

        // 动态创建泛型的LogInfoRequestResult<T>并赋值
        var resultGenericType = typeof(LogInfoRequestResult<>).MakeGenericType(modelType);
        var result = Activator.CreateInstance(resultGenericType);
        result.GetType().GetProperty(nameof(LogInfoRequestResult<IRequestModel>.Raw))?
              .SetValue(result, rawData);

        return (IResult)result;
    }
}

方案二:利用Newtonsoft.Json的自定义转换器(进阶)

如果想让序列化过程更透明,可以自定义一个JsonConverter,直接根据method字段反序列化为对应的泛型类型:

public class RequestResultConverter : JsonConverter<IResult>
{
    private static readonly Dictionary<string, Type> _modelTypeMap = 
        new(StringComparer.OrdinalIgnoreCase)
        {
            { "Model", typeof(LogInfoRequestResult<Model>) },
            { "OtherModel", typeof(LogInfoRequestResult<OtherModel>) }
            // 同样可以自动注册
        };

    public override IResult ReadJson(JsonReader reader, Type objectType, IResult existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        var jObject = JObject.Load(reader);
        if (!jObject.TryGetValue("method", out var methodToken))
        {
            throw new JsonSerializationException("缺少method字段");
        }

        var methodName = methodToken.Value<string>();
        if (!_modelTypeMap.TryGetValue(methodName, out var resultType))
        {
            throw new JsonSerializationException($"不支持的method:{methodName}");
        }

        return (IResult)jObject.ToObject(resultType, serializer);
    }

    public override void WriteJson(JsonWriter writer, IResult value, JsonSerializer serializer)
    {
        // 如果需要序列化IResult,在这里实现逻辑
        throw new NotImplementedException();
    }
}

使用的时候直接反序列化为IResult即可:

var result = JsonConvert.DeserializeObject<IResult>(json, new RequestResultConverter());

为什么不用switch?

  • 维护成本:几百个模型的switch会非常冗长,新增/删除模型都要修改这个方法,容易出错
  • 开闭原则:上述方案遵循开闭原则,新增模型只需要添加类(或标记Attribute),无需修改转换逻辑
  • 可靠性:用JObject解析JSON比Regex更稳定,能处理各种合法的JSON格式(比如转义字符、字段顺序变化等)

内容的提问来源于stack exchange,提问作者Bruno

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 06:49:59