Как да използвате 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‹ISomething›› - 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