Как проанализировать значение TimeSpan в Newtonsoft JSON

Я хотел бы проанализировать строку JSON и использовать свойство token.Type для обнаружения значений типа JTokenType.TimeSpan.

Я не могу понять, как выразить TimeSpan в моей входной строке, кажется, все интерпретируется как JTokenType.String.

var timeSpanString = TimeSpan.FromHours(1).ToString();
testString = string.Format(@"{{""Value"": ""{0}"" }}", timeSpanString);
var statObject = JObject.Parse(testString);
JToken token = statObject["Value"];
var tokenValue = token.ToString();
var tokenType = token.Type; // JTokenType.String

Я даже пробовал:

JValue jValue = new JValue("test");
jValue.Value = TimeSpan.FromHours(1);
bool isTimeSpan = jValue.Type == JTokenType.TimeSpan; // true!
testString = string.Format(@"{{""Value"": ""{0}"" }}", jValue.Value);
var statObject = JObject.Parse(testString);
JToken token = statObject["Value"];
var tokenValue = token.ToString();
var tokenType = token.Type; // JTokenType.String

Который, по крайней мере, создает объект JValue tokenType JTokenType.TimeSpan, но все же отображается как JTokenType.String при его анализе.

Это отлично работает для объектов DateTime. Как я могу выразить входную строку так, чтобы тип анализируемого значения был JTokenType.TimeSpan?


person s d    schedule 21.11.2012    source источник
comment
Вы смотрите на обработку входных данных с определенной структурой или хотите найти любой экземпляр временного интервала в блоке Json?   -  person nick_w    schedule 21.11.2012
comment
Не уверен, что вы подразумеваете под определенной структурой. Входными данными будет строка JSON, содержащая значение, которое может быть одного из нескольких типов: строка, DateTime, TimeSpan и некоторые другие.   -  person s d    schedule 21.11.2012
comment
@LB - Это не очень помогает. Мне нужно знать, как форматировать входную строку, чтобы синтаксический анализатор превращал эту строку в JObject, который содержит токен JValue типа JTokenType.TimeSpan.   -  person s d    schedule 22.11.2012
comment
@sd Сериализаторы существуют для того, чтобы скрыть от вас эти детали. Просто подумайте об этом.   -  person L.B    schedule 22.11.2012
comment
Но ваше решение не решает мою конкретную проблему: var ts = JsonConvert.SerializeObject(TimeSpan.FromHours(1)); testString = string.Format(@{{Value: {0} }}, ts); var statObject = JObject.Parse(testString); Токен JToken = statObject[Value]; var tokenValue = token.ToString(); var tokenType = token.Type; // JTokenType.String — ожидать JTokenType.TimeSpan Мой код должен принимать десериализованный объект и вести себя по-разному для разных типов.   -  person s d    schedule 22.11.2012
comment
Этот метод работал у меня: stackoverflow.com/a/14319926/298573   -  person VahidN    schedule 04.04.2020


Ответы (3)


Основываясь на том, что я уже некоторое время видел при использовании JSON.NET, вы никогда не будете, с настройками по умолчанию, анализировать строку и извлекать токен с типом JTokenType.TimeSpan (то же самое для некоторых других типов, таких как Guid или Uri ). У меня есть довольно хорошее представление о том, почему это так (основываясь на моем опыте работы с DataContractJsonSerializer несколько лет назад).

По сути, это вопрос того, сколько информации синтаксический анализатор может извлечь из ввода. JSON — это очень простой синтаксис, который знает только о числах, логических значениях и строках (в дополнение к массивам и объектам). Многие типы CLR не имеют собственного типа JSON (Uri, DateTime, DateTimeOffset, TimeSpan и т. д.), поэтому при чтении данных любым синтаксическим анализатором JSON он попытается использовать наилучшее совпадение.

Если вы десериализуете строку JSON в тип данных CLR, то у сериализатора есть дополнительная информация, которую он может использовать для устранения неоднозначности того, на что сопоставляется строка JSON — тип поля/свойства, в которое десериализуется значение. Однако при десериализации данных JSON в граф объектов JToken дополнительная информация отсутствует, и JSON.NET должен выбрать один тип. Наиболее естественным типом для десериализации строки JSON является строка CLR.

Но почему даты правильно десериализуются как JTokenType.Date? IIRC, средство чтения JSON.NET имеет специальный код для дат (управляемый перечислением DateParseHandling), который пытается сопоставить проанализированные строки с некоторыми предопределенными форматами (либо ISO 8601, либо старый формат Microsoft ASP.NET AJAX), и если он находит строку, которая соответствует ей, она будет читать ее как DateTime (или DateTimeOffset) вместо строки. Я не знаю, возможно ли расширить это поведение, чтобы также поддерживать TimeSpan или другие типы, но я не удивлюсь, поскольку расширяемость в JSON.NET довольно хороша.

person carlosfigueira    schedule 22.11.2012
comment
Дополнительная информация о волшебном анализе даты/времени и о том, как его избежать: github.com/JamesNK /Newtonsoft.Json/issues/862 - person EM0; 06.05.2021

Если вы пытаетесь проанализировать TimeSpan, его необходимо заключить в кавычки: '"12:00:00"'

Если вы сериализуете TimeSpan и посмотрите на результат строки, он будет выглядеть так: "\"12:00:00\""

По крайней мере, это сработало для меня с помощью NewtonSoft.JsonConvert. Строка в моей БД "12:00:00" (включая кавычки).

И использование JsonConvert.DeserializeObject(dbString) возвращает нормально.

person boylec1986    schedule 20.05.2016

Просто столкнулся с той же проблемой и смог сделать это следующим образом:

string json = "{ \"span\": \"00:00:15\"}";

JToken token = JToken.Parse(json);

TimeSpan span = token["span"].ToObject<TimeSpan>();
person Helge Mahrt    schedule 03.07.2018