如何根据对象类型将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
相关产品推荐
相关产品推荐

