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

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

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.

Ответ 1

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

JsonReader reader = token.CreateReader();

Ответ 2

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

streamReader.BaseStream.Position = 0;

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

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

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

Ответ 3

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

  • Установить JsonTextReader.CloseInput = false
  • Уничтожьте JsonTextReader (закрыв оператор using)
  • Установить StreamReader.BaseStream.Position = 0
  • Создайте новый 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);
    }

}

Ответ 4

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

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