输入字符串格式错误不正确,但仍能从LINQ到XML查询获取解析值

时间:2015-06-05 15:45:24

标签: c# xml linq parsing linq-to-xml

我有一个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)时,没有正确解析的东西,但我不明白为什么有两个原因:

  1. 我手动检查过,xml文件中ID属性中的每个值都是真实的uint(只是数字,没有空格等)。

  2. 当不使用names.Count().ToList()时,虽然在查看变量时确实提到了调试模式中的错误,但仍找到与id关联的名称并且该函数正确地返回它。

  3. 为什么我的uint.Parse(...)在这给我带来麻烦?

1 个答案:

答案 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>