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

如何根据对象类型将JSON反序列化为两个不同的C#类?

问题描述

我需要读取以下格式的JSON文件:

{
    "A":
    {
        "type": "option_a",
        "state": 0
    },
    
    "B":
    {
        "type": "option_b",
        "state": 1
    },
    
    "C":
    {
        "type": "option_a",
        "state": 0
    },
    
    ...
    
    "Z":
    {
        "MODE A":
        {
            "status a": 0,
            "status b": 0
        },
        "MODE B":
        {
            "status a": 0,
            "status b": 1
        },
        "MODE C":
        {
            "status a": 1,
            "status b": 0
        }
    }
}

对应的C#类我定义如下:

public class ClassA
{
    public string Type { get; set; }
    public int State { get; set; }
}

// 处理'Z'结构:
public class ClassB
{
    public ClassBInternalStructure Mode { get; set; }
}

public class ClassBInternalStructure
{
    public int StatusA { get; set; }
    public int StatusB { get; set; }
}

我想用Newtonsoft的JsonConvert实现解析,已经写了C# 8下的部分转换器代码,但ReadJson方法逻辑和调用部分缺失,希望补全代码并指导正确调用转换器:

public class MyJsonConverter : JsonConverter
{
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        if (token.Type == JTokenType.Object)
        {
            // 待补全逻辑
        }
        else if (token.Type == JTokenType.String)
        {
            // 待补全逻辑
        }
        else
        {
            throw new NotSupportedException("不支持的Token类型");
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override bool CanConvert(Type objectType)
    {
        throw new NotImplementedException();
    }
}

调用部分代码也未完成:

public class JsonParser
{
    public void Parsing(string filePath)
    {
        try
        {
            using StreamReader sr = new(filePath);
            string JsonData = File.ReadAllText(filePath);

            // 是否需要另一个MyJsonConverter重写类?

            ???.ReadJson(????, null, null, new Newtonsoft.Json.JsonSerializer());
        }
        catch (Exception)
        {
            throw;
        }
    }
}
解决方案

你的JSON根结构是混合类型的键值对:大部分键(A-Y)对应ClassA,键Z对应多组ClassBInternalStructure。直接用JObject解析比自定义转换器更简洁,以下是两种实现方案:

方案一:直接用JObject解析(推荐)

无需自定义转换器,直接遍历解析每个节点:

// 先给类添加JsonProperty特性,映射JSON字段名
public class ClassA
{
    [JsonProperty("type")]
    public string Type { get; set; }
    
    [JsonProperty("state")]
    public int State { get; set; }
}

public class ClassBInternalStructure
{
    [JsonProperty("status a")]
    public int StatusA { get; set; }
    
    [JsonProperty("status b")]
    public int StatusB { get; set; }
}

// 解析逻辑
public class JsonParser
{
    public void Parsing(string filePath)
    {
        try
        {
            string jsonData = File.ReadAllText(filePath);
            JObject root = JObject.Parse(jsonData);

            // 存储A-Y的ClassA实例
            Dictionary<string, ClassA> classAItems = new();
            // 存储Z下的所有MODE
            Dictionary<string, ClassBInternalStructure> zModes = new();

            foreach (var property in root.Properties())
            {
                if (property.Name != "Z")
                {
                    ClassA item = property.Value.ToObject<ClassA>();
                    classAItems.Add(property.Name, item);
                }
                else
                {
                    foreach (var modeProp in property.Value.Children<JProperty>())
                    {
                        ClassBInternalStructure mode = modeProp.Value.ToObject<ClassBInternalStructure>();
                        zModes.Add(modeProp.Name, mode);
                    }
                }
            }

            // 这里可以按需使用解析后的数据,比如打印测试
            foreach (var kvp in classAItems)
            {
                Console.WriteLine($"{kvp.Key}: Type={kvp.Value.Type}, State={kvp.Value.State}");
            }
            foreach (var kvp in zModes)
            {
                Console.WriteLine($"{kvp.Key}: StatusA={kvp.Value.StatusA}, StatusB={kvp.Value.StatusB}");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"解析出错:{ex.Message}");
            throw;
        }
    }
}

方案二:自定义转换器实现

如果必须用自定义转换器,可针对根容器类编写:

// 根容器类,统一存储解析结果
public class RootContainer
{
    public Dictionary<string, ClassA> ClassAItems { get; set; }
    public Dictionary<string, ClassBInternalStructure> ZModes { get; set; }
}

// 自定义转换器
public class RootConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(RootContainer);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject root = JObject.Load(reader);
        RootContainer container = new()
        {
            ClassAItems = new Dictionary<string, ClassA>(),
            ZModes = new Dictionary<string, ClassBInternalStructure>()
        };

        foreach (var prop in root.Properties())
        {
            if (prop.Name != "Z")
            {
                container.ClassAItems.Add(prop.Name, prop.Value.ToObject<ClassA>(serializer));
            }
            else
            {
                foreach (var modeProp in prop.Value.Children<JProperty>())
                {
                    container.ZModes.Add(modeProp.Name, modeProp.Value.ToObject<ClassBInternalStructure>(serializer));
                }
            }
        }
        return container;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

// 调用转换器的解析逻辑
public class JsonParser
{
    public void Parsing(string filePath)
    {
        try
        {
            string jsonData = File.ReadAllText(filePath);
            JsonSerializerSettings settings = new()
            {
                Converters = { new RootConverter() }
            };

            RootContainer container = JsonConvert.DeserializeObject<RootContainer>(jsonData, settings);
            // 按需使用container中的数据
        }
        catch (Exception ex)
        {
            Console.WriteLine($"解析出错:{ex.Message}");
            throw;
        }
    }
}

关键注意事项

  • 修正示例JSON中的多余逗号(最后一个键值对后不要加逗号,否则解析会报错)
  • 必须用JsonProperty特性映射JSON中的带空格/蛇形命名到C#的驼峰命名属性
  • 混合类型JSON优先用JObject直接解析,自定义转换器适合更复杂的类型判断场景

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 23:40:34