#c# #json #json.net #deserialization
#c# #json #json.net #десериализация
Вопрос:
Предположим, что следующий JSON:
{
"channel": "751853588527054938"
"message": "751853745758928908"
}
И следующая часть кода:
[JsonConverter(typeof(TextChannelConverter))]
[JsonProperty("channel")]
public ITextChannel Channel;
[JsonConverter(typeof(UserMessageConverter))]
[JsonProperty("message")]
public IUserMessage Message;
Что я пытаюсь сделать, так это то, что я хочу иметь пользовательский конвертер для десериализации для обоих этих типов, но проблема в том, что я не могу получить сообщение, если у меня есть только его идентификатор, мне также нужно знать идентификатор канала для этого (точнее, сообщение извлекается с помощью ITextChannel#GetMessageAsync (ulong id)). Есть ли способ получить доступ к идентификатору канала или даже к объекту канала в UserMessageConverter?
Я попытался загрузить весь 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);
}
Комментарии:
1. Это кажется странным способом использования
JsonConverter
. Почему бы вам просто не десериализовать в строку, что и есть … затем, после десериализации, обработайте данные. Похоже, вы пытаетесь убить 2 зайцев одним выстрелом.. но почему? Скорее всего, вам понадобится выполнять операции ввода-вывода, связанные сReadJson
иReadJson
, не асинхронно, поэтому оно будет заблокировано.
Ответ №1:
Если одно из свойств зависит от другого, то вам нужно будет создать одно JsonConverter
, которое обрабатывает родительский объект, а не два отдельных преобразователя для каждого из дочерних свойств.
Вы не сказали, какой класс содержит свойства Channel
и Message
в вашей модели, поэтому я просто назову его 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).Resu<
return new Chat { Channel = channel, Message = message };
}
}