我有一个xml文件,我可以从某个节点获取ID
。节点具有以下结构:
<Bistot ID="1223"/>
<Compressed_Bistot ID="28388"/>
<Compressed_Monoclinic_Bistot ID="28389"/>
...
它们在我的xml文件中也处于不同的级别(它太大了,无法在此列出所有内容)。
为了做到这一点,我使用了一个执行LINQ查询的函数:
public String GetItemName(uint id)
{
IEnumerable<String> names = _xmlFile.Descendants()
.Where(x => x.Attributes().Any(a => a.Name.LocalName == "ID") && uint.Parse(x.Attributes().First(a => a.Name.LocalName == "ID").Value) == id)
.Select(t => t.Name.LocalName);
return names.ElementAt(0);
}
在这种形式中,如果我提供的id
存在并且names
变量实际上有一个条目,它就可以正常工作。如果不是,则会在return names.ElementAt(0);
处引发异常,因为索引0
处没有元素。此时,在调试模式下,如果我去检查变量names
,我确实看到它提到了Input string was not in a correct format
,但没有错误是引发并且该函数返回了好处与name
相关联的id
。
我还尝试了以下表单,以便在LINQ请求在xml文件中找不到任何关联名称时删除发生的异常:
public String GetItemName(uint id)
{
IEnumerable<String> names = _xmlFile.Descendants()
.Where(x => x.Attributes().Any(a => a.Name.LocalName == "ID") && uint.Parse(x.Attributes().First(a => a.Name.LocalName == "ID").Value) == id)
.Select(t => t.Name.LocalName);
if (names.Count() != 0) // Error raised here
{
return names.ElementAt(0);
}
else
{
return "";
}
}
这就是我的问题发生的地方,因为在这种情况下,当我调用names.Count()
时,会引发Input string was not in a correct format
(类型为FormatException
)错误,然后我的应用程序不会继续/完整。
我还试图在LINQ查询结束时调用.ToList()
,因为我有一个警告告诉我这样做。但在这种情况下,直接在我的LINQ查询中引发Input string was not in a correct format
错误,而不是names.Count()
调用。
我确实理解了这个错误的本质,当我在LINQ查询中调用uint.Parse(x.Attributes().First(a => a.Name.LocalName == "ID").Value)
时,没有正确解析的东西,但我不明白为什么有两个原因:
我手动检查过,xml文件中ID
属性中的每个值都是真实的uint
(只是数字,没有空格等)。
当不使用names.Count()
或.ToList()
时,虽然在查看变量时确实提到了调试模式中的错误,但仍找到与id
关联的名称并且该函数正确地返回它。
为什么我的uint.Parse(...)
在这给我带来麻烦?
答案 0 :(得分:1)
问题在于,当你使用ElementAt(0)
时,它只需要找到第一个元素 - 所以如果后来有一个ID
元素,其值无效(我确定有),你不会打它。当您致电Count()
或ToList()
时,它会对查询的整个进行迭代,从而导致问题。
实际上,你的代码效率非常低,但是多次评估 - 写得更好:
public String GetItemName(uint id)
{
IEnumerable<String> names = ...; // Query as before
return names.FirstOrDefault() ?? "";
}
我还建议使用LINQ to XML提供的显式转换,而不是手动调用uint.Parse
:
IEnumerable<String> names = _xmlFile.Descendants()
.Where(x => (uint?) x.Attributes()
.Where(a => a.Name.LocalName == "ID")
.FirstOrDefault() == id)
.Select(t => t.Name.LocalName);
我们在这里找到第一个ID
属性,将其转换为uint?
(如果没有此类属性,则为null
),然后将其与id
进行比较。< / p>