Ответ 1
Это почти то, к чему предназначен общий метод Value()
. Вы получите именно то поведение, которое хотите, если объединить его с типами значений с нулевым значением и оператором ??
:
width = jToken.Value<double?>("width") ?? 100;
Какая наилучшая практика для получения значений JSON, которые могут даже не существовать на С#, используя Json.NET?
Сейчас я имею дело с провайдером JSON, который возвращает JSON, который иногда содержит определенные пары ключ/значение, а иногда и нет. Я использовал (возможно, неправильно) этот метод для получения моих значений (пример для получения двойного):
if(null != jToken["width"])
width = double.Parse(jToken["width"].ToString());
else
width = 100;
Теперь это прекрасно работает, но когда их много, это громоздко. Я закончил писать метод расширения, и только после, написав его, я задался вопросом, может быть, я был глупым... в любом случае, вот метод расширения (я включаю только случаи для double и string, но в действительности у меня есть еще немало):
public static T GetValue<T>(this JToken jToken, string key,
T defaultValue = default(T))
{
T returnValue = defaultValue;
if (jToken[key] != null)
{
object data = null;
string sData = jToken[key].ToString();
Type type = typeof(T);
if (type is double)
data = double.Parse(sData);
else if (type is string)
data = sData;
if (null == data && type.IsValueType)
throw new ArgumentException("Cannot parse type \"" +
type.FullName + "\" from value \"" + sData + "\"");
returnValue = (T)Convert.ChangeType(data,
type, CultureInfo.InvariantCulture);
}
return returnValue;
}
И вот пример использования метода расширения:
width = jToken.GetValue<double>("width", 100);
Кстати, пожалуйста, простите, что может быть очень глупым вопросом, так как кажется, что что-то должно быть встроенной функцией для... Я пытался Google, и Json.NET, однако я либо не способен найти решение моего вопроса, либо неясно в документации.
Это почти то, к чему предназначен общий метод Value()
. Вы получите именно то поведение, которое хотите, если объединить его с типами значений с нулевым значением и оператором ??
:
width = jToken.Value<double?>("width") ?? 100;
Я бы написал GetValue
, как показано ниже
public static T GetValue<T>(this JToken jToken, string key, T defaultValue = default(T))
{
dynamic ret = jToken[key];
if (ret == null) return defaultValue;
if (ret is JObject) return JsonConvert.DeserializeObject<T>(ret.ToString());
return (T)ret;
}
Таким образом вы можете получить значение не только основных типов, но и сложных объектов. Вот пример
public class ClassA
{
public int I;
public double D;
public ClassB ClassB;
}
public class ClassB
{
public int I;
public string S;
}
var jt = JToken.Parse("{ I:1, D:3.5, ClassB:{I:2, S:'test'} }");
int i1 = jt.GetValue<int>("I");
double d1 = jt.GetValue<double>("D");
ClassB b = jt.GetValue<ClassB>("ClassB");
Вот как вы можете проверить, существует ли токен:
if (jobject["Result"].SelectToken("Items") != null) { ... }
Он проверяет, существует ли "Элемент" в "Результате".
Это не рабочий пример, который вызывает исключение:
if (jobject["Result"]["Items"] != null) { ... }
Вы можете просто typecast, и он сделает для вас преобразование, например.
var with = (double?) jToken[key] ?? 100;
Он автоматически вернет null
, если указанный ключ отсутствует в объекте, поэтому нет необходимости его проверять.
TYPE variable = jsonbody["key"]?.Value<TYPE>() ?? DEFAULT_VALUE;
например.
bool attachMap = jsonbody["map"]?.Value<bool>() ?? false;