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

如何在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调用该转换器,具体步骤如下:

  1. 定义数组元素的实体类
    创建用于解析数组中对象类型的类:
public class GamePlayMessageItem
{
    public string name { get; set; }
    public string argType { get; set; }
}
  1. 创建数组元素的自定义转换器
    该转换器负责区分数组中的对象和字符串类型:
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);
    }
}
  1. 标记需要转换的列表字段
    在GamePlayComplexMessage的message字段上添加转换器标记:
public class GamePlayComplexMessage
{
    public string type;
    [JsonConverter(typeof(GamePlayMessageItemConverter))]
    public List<object> message;
}
  1. 修改主转换器的数组处理逻辑
    不再直接使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 05:07:23