如何在C#自定义转换器中嵌套调用转换器处理复杂JSON多格式内容
处理复杂JSON反序列化的数组多格式问题
给定如下JSON结构,其中message字段存在两种格式:一种是包含alert对象的结构,另一种是混合对象与字符串的数组,且无法修改JSON格式:
{ "messages": [ { "date": "2023-05-19T17:58:17.329Z", "message": { "alert": { "type": "info", "message": [ { "name": "AshesAppTest1", "argType": "nonAvatarPlayer" }, " has connected to the game server" ] } }, "activePlayer": null }, { "date": "2023-05-19T18:56:32.304Z", "message": [ { "name": "AshesAppTest2", "argType": "player" }, " ", "Hello world!" ] } ] }
现有C#类结构及自定义转换器如下,但在处理数组时无法正确解析混合类型元素:
public class GamePlayMessage { public string date { get; set; } public GamePlayPlayer activePlayer { get; set; } [JsonProperty("message")] [JsonConverter(typeof(GamePlayMessageDataConverter))] public GamePlayMessageData MessageData { get; set; } } public class GamePlayMessageData { [JsonProperty("alert")] public GamePlayComplexMessage ComplexMessage { get; set; } } public class GamePlayComplexMessage { public string type; public List<object> message; } class GamePlayMessageDataConverter : JsonConverter { public override bool CanConvert(Type objectType) { return (objectType == typeof(GamePlayMessageData)); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { JToken token = JToken.Load(reader); if (token.Type == JTokenType.Object) { return token.ToObject<GamePlayMessageData>(); } else if (token.Type == JTokenType.Array) { Debug.Log(token); return new GamePlayMessageData { ComplexMessage = new GamePlayComplexMessage { type = "noType", message = new List<object>(token.ToArray<object>()) } }; } return null; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { serializer.Serialize(writer, value); } }
解决方案
要解决数组内混合类型的解析问题,需要添加一个针对数组元素的自定义转换器,并在主转换器中利用JsonSerializer调用该转换器,具体步骤如下:
- 定义数组元素的实体类
创建用于解析数组中对象类型的类:
public class GamePlayMessageItem { public string name { get; set; } public string argType { get; set; } }
- 创建数组元素的自定义转换器
该转换器负责区分数组中的对象和字符串类型:
class GamePlayMessageItemConverter : JsonConverter { public override bool CanConvert(Type objectType) { return objectType == typeof(object); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { JToken token = JToken.Load(reader); if (token.Type == JTokenType.Object) { return token.ToObject<GamePlayMessageItem>(); } else { return token.ToString(); } } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { serializer.Serialize(writer, value); } }
- 标记需要转换的列表字段
在GamePlayComplexMessage的message字段上添加转换器标记:
public class GamePlayComplexMessage { public string type; [JsonConverter(typeof(GamePlayMessageItemConverter))] public List<object> message; }
- 修改主转换器的数组处理逻辑
不再直接使用ToArray<object>,而是通过JsonSerializer逐个解析数组元素,自动应用上述转换器:
class GamePlayMessageDataConverter : JsonConverter { public override bool CanConvert(Type objectType) { return objectType == typeof(GamePlayMessageData); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { JToken token = JToken.Load(reader); if (token.Type == JTokenType.Object) { return token.ToObject<GamePlayMessageData>(serializer); } else if (token.Type == JTokenType.Array) { var complexMsg = new GamePlayComplexMessage { type = "noType", message = new List<object>() }; foreach (var itemToken in token.Children()) { var item = serializer.Deserialize(itemToken.CreateReader(), typeof(object)); complexMsg.message.Add(item); } return new GamePlayMessageData { ComplexMessage = complexMsg }; } return null; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { serializer.Serialize(writer, value); } }
修改后,主转换器在处理数组时会通过serializer.Deserialize自动调用GamePlayMessageItemConverter,正确解析数组中的对象和字符串元素,完成整个JSON的反序列化。
内容的提问来源于stack exchange,提问作者Timothy Cathcart
相关产品推荐
相关产品推荐

