Возникли проблемы с Nullable

#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