#c# #xml #linq #nullable
#c# #xml #linq #nullable
Вопрос:
Я использую LINQ и XDocument для анализа XML-файла. Некоторые поля в XML не являются фиксированными, поскольку иногда они могут быть двойными или строковыми. Обычно это будет double, но строка будет указывать, что данные были недоступны.
Например:
<current_observation>
<temp_c>12.1</temp_c>
<temp_c>NA</temp_c>
</current_observation>
Я читаю в полях XML, а затем устанавливаю свойства в новом экземпляре объекта. Вот так:
var data = from i in weatherResponse.Descendants("current_observation")
select new CurrentConditions
{
// Attempt to parse. Set to null if not a double.
// This is one of the areas I'm having trouble with.
TemperatureC = Utilities.ParseDoubleValue(i.Element("temp_c"))
// If I use the following line instead then it works without problem.
// But this misses out all of the safe parsing.
// TemperatureC = (double)i.Element("temp_c")
};
Я решил использовать Nullable
тип, чтобы я мог использовать TryParse
либо для разбора поля на double , либо, если это было невозможно, установить для свойства значение null.
Вот код, который я использую, чтобы попытаться проанализировать поле:
public static class Utilities
{
public static double? ParseDoubleValue(object inputValue)
{
if (inputValue == null)
return null;
double returnValue;
return double.TryParse(inputValue.ToString(), out returnValue) ? returnValue : (double?)null;
}
}
Однако, похоже, что где-то в моем коде на самом деле поле не разбирается должным образом, потому что, если я сделаю это:
if(currentConditions.TemperatureC.HasValue)
Console.WriteLine("Has a value: {0}", currentConditions.TemperatureC.Value);
else
Console.WriteLine("Not Avaliable.");
Тогда значение HasValue всегда будет возвращать false .
Мой вопрос: почему мой метод попытки проанализировать значение не работает? Я неправильно понял использование типов TryParse
и nullable ?
Комментарии:
1. установите некоторые точки останова и проверьте состояние вашего кода в разных точках
2. Ваша логика для ParseDoubleValue немного окольная. Вам не нужен блок if в начале, поскольку у вас уже есть троичный оператор, и вам не нужно явно приводить null к
double?
.
Ответ №1:
XElement
определяет явные преобразования типов в различные числовые типы. Следовательно, (double)i.Element("temp_c")
разрешено и преобразует значение XElement
в двойной тип данных (через внутренний вызов Double.Parse
).
Когда XElement
передается в качестве аргумента типа object
вашему Utilities.ParseDoubleValue
методу, вы передаете все XElement
. Вызов inputValue.ToString()
возвращает не 12.1
, а, скорее <temp_c>12.1</temp_c>
, значение XML с отступом для узла. И double.TryParse("<temp_c>12.1</temp_c>")
, конечно же, потерпит неудачу.
Ошибка заключается в том, что вы, скорее всего, захотите предоставить этому методу строковое значение XElement
, а не сам XElement . Это простой вопрос изменения:
TemperatureC = Utilities.ParseDoubleValue(i.Element("temp_c"))
Для
TemperatureC = Utilities.ParseDoubleValue(i.Element("temp_c").Value)
Во-вторых, в качестве защитной меры вы можете пересмотреть сигнатуру метода для своего метода:
public static double? ParseDoubleValue(object inputValue)
Это будет принимать любой объект, но в конечном итоге вы заинтересованы в преобразовании строки, которую предоставляет вызывающий. Изменение его на прием только строки гарантирует, что вызывающие пользователи предоставят строку, а невыполнение этого требования приведет к ошибке компиляции.
public static double? ParseDoubleValue(string inputValue)
Комментарии:
1. Спасибо, это сработало. Кроме того, ваш подробный ответ помог мне понять это гораздо более четко.
Ответ №2:
i.Element возвращает элемент XElement, а не значение. И, конечно, это не будет разбираться на число. Вам нужно i.Element("temp_c").Value