我正在使用LINQ和XDocument来解析XML文件。 XML中的某些字段不是固定的,因为它们有时可能是双字符串或字符串。通常它会是一个双精度数字,但是一个字符串表示数据不可用。
例如:
<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
和可空类型的用法?
答案 0 :(得分:2)
i.Element返回一个XElement,而不是值。而且,当然,这对于一个数字来说是不可解析的。您需要i.Element("temp_c").Value
答案 1 :(得分:2)
XElement
为各种数字类型定义explicit type conversions。因此,(double)i.Element("temp_c")
被允许并将XElement
的{{3}}转换为双数据类型(通过内部调用Double.Parse
)。
当XElement
作为object
类型的参数传递到您的Utilities.ParseDoubleValue
方法时,您将传递整个XElement
。对inputValue.ToString()
的调用不返回12.1
,而是返回<temp_c>12.1</temp_c>
,value。当然,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)