首页 > 解决方案 > 在自定义 JsonConverter 中使用来自 json 的另一个属性

问题描述

假设以下 JSON:

{
  "channel": "751853588527054938"
  "message": "751853745758928908"
}

以及以下部分代码:

        [JsonConverter(typeof(TextChannelConverter))]
        [JsonProperty("channel")]
        public ITextChannel Channel;

        [JsonConverter(typeof(UserMessageConverter))]
        [JsonProperty("message")]
        public IUserMessage Message;

我想要做的是,我想为这两种类型的去实现一个自定义转换器,但问题是,如果我只有它的 ID,我无法收到消息,我还需要知道这样做的通道 ID(更准确地说,使用 ITextChannel#GetMessageAsync(ulong id) 检索消息)。有没有办法在 UserMessageConverter 中访问通道的 ID 甚至通道对象?

我尝试从阅读器加载整个 JSON

    class UserMessageConverter : JsonConverter
    {
        public override bool CanWrite => false;
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException();

        public override bool CanConvert(Type objectType) => objectType == typeof(IUserMessage);

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            JObject jobj = JObject.Load(reader);
            return null;
        }

但它发出一个例外:

Newtonsoft.Json.JsonReaderException: Error reading JObject from JsonReader. Current JsonReader item is not an object: Integer. Path 'message', line 1, position 75.

作为参考,TextChannelConverter的代码:

        class TextChannelConverter : JsonConverter
        {
        public override bool CanWrite => false;
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException();

        public override bool CanConvert(Type objectType) => objectType == typeof(ITextChannel);

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (reader.Value == null)
                return null;

            ulong channelid = ulong.Parse(reader.Value.ToString());

            return Essentials.FireLands.GetChannel(channelid);
        }

标签: c#jsonjson.netdeserialization

解决方案


如果其中一个属性依赖于另一个,那么您需要制作一个JsonConverter处理父对象的单一属性,而不是为每个子属性创建两个单独的转换器。

你没有说什么类包含你的模型中的ChannelandMessage属性,所以我只是Chat为了举例而称它为。

所以你会有:

[JsonConverter(typeof(ChatConverter))]
class Chat
{    
    public ITextChannel Channel { get; set; }
    public IUserMessage Message { get; set; }
}

然后你的转换器可能看起来像这样:

class ChatConverter : JsonConverter
{
    public override bool CanConvert(Type objectType) => objectType == typeof(Chat);
    public override bool CanWrite => false;
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException();

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.Value == null)
            return null;

        JObject obj = JObject.Load(reader);
        ulong channelId = (ulong)obj["channel"];
        ulong messageId = (ulong)obj["message"];

        ITextChannel channel = Essentials.FireLands.GetChannel(channelId);
        IUserMessage = channel.GetMessageAsync(messageId).Result;

        return new Chat { Channel = channel, Message = message };
    }
}

推荐阅读