Как использовать JsonTextReader дважды

Мне дан поток данных json, который содержит поле с именем «тип». Это поле типа описывает тип объекта, который необходимо создать во время выполнения. Похоже, я не могу дважды использовать JsonTextReader и не могу найти способ сбросить средство чтения текста в начало.

using (var streamReader = new StreamReader(stream, Encoding))
using (var jsonTextReader = new JsonTextReader(streamReader))
{
    JToken token = JObject.Load(jsonTextReader);
    var type = (string) token.SelectToken("type");
    var modelType = Type.GetType("Project." + type + ", Project");

    // Fails here
    var obj = serializer.Deserialize(jsonTextReader, modelType);
}

Я получаю это сообщение об ошибке. Неожиданный токен при десериализации объекта: EndObject.


person Phil    schedule 05.03.2012    source источник


Ответы (4)


Вы можете создать JsonReader из JToken.

JsonReader reader = token.CreateReader();
person James Newton-King    schedule 06.03.2012
comment
Это не работает, когда искомый тип находится в универсальном массиве, например ‹IEnumerable‹ISsomething›› - person hvk; 20.11.2018

Чтобы сбросить средство чтения до начала, установите для свойства Position базового потока значение 0.

streamReader.BaseStream.Position = 0;

Изменить: хотя это приведет к сбросу вашего базового потока, jsonTextReader по определению только вперед, что означает, что его номер строки и позиция доступны только для чтения. Чтобы это работало, вам нужно сбросить позицию streamReader, а затем передать ее в новый объект JsonTextReader.

Так что, к сожалению, Фил, нет возможности прочитать JsonTextReader дважды, так как он предназначен только для пересылки.

Ссылка: http://james.newtonking.com/projects/json/help/html/T_Newtonsoft_Json_JsonTextReader.htm "Представляет собой средство чтения, которое обеспечивает быстрый, некэшированный, прямой доступ к сериализованным данным Json".

person Despertar    schedule 06.03.2012
comment
Вы уверены, что это будет работать правильно? И StreamReader, и JsonTextReader, вероятно, сохраняют внутреннее состояние, которое не будет сброшено при этом. - person svick; 06.03.2012

Я расскажу об использовании JsonTextReader в формате с эффективным использованием памяти, избегая кучи больших объектов и т. д., в моем блоге в соответствии с рекомендациями Джеймса Ньютона Кинга. Вы можете использовать этот и предоставленный код для многократного чтения вашего JSON, не беспокоясь о базовой реализации JsonTextReader.

Комментарии и отзывы всегда приветствуются.

person Paul Mooney    schedule 25.09.2013

Я провел еще несколько тестов и обнаружил, что работает следующее.

  1. Установить JsonTextReader.CloseInput = false
  2. Уничтожить JsonTextReader (закрыв оператор using)
  3. Установить StreamReader.BaseStream.Position = 0
  4. Создайте новый JsonTextReader

Это будет выглядеть примерно так:

using (var streamReader = new StreamReader(stream, encoding))
{
    Type modelType = null;

    using (var jsonTextReader = new JsonTextReader(streamReader))
    {
        jsonTextReader.CloseInput = false;

        JToken token = JObject.Load(jsonTextReader);
        string type = (string)token.SelectToken("type");
        modelType = Type.GetType("Project." + type + ", Project");
    }

    streamReader.BaseStream.Position = 0;

    using (var jsonTextReader = new JsonTextReader(streamReader))
    {
        var obj = serializer.Deserialize(jsonTextReader, modelType);
    }

}
person tstuts    schedule 06.03.2012
comment
Это не сработает. Если вы не укажете параметр leaveOpen в конструкторе StreamReader, он закроет базовый поток. Если вы исправите это, это может сработать, если код в вопросе сработает, но это не так. - person svick; 06.03.2012
comment
Мой исходный пост был протестирован, но неправильно. Я обновил его. - person tstuts; 06.03.2012