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

Input string was not in a correct format error, but still able to get parsed value from LINQ to XML query

我有一个 xml 文件,我可以从中从某些节点获取 IDs。节点具有以下结构:

<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,但是 raised 和函数没有错误returns 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 formatFormatException 类型)错误,然后我的应用程序不会continue/complete.

我也曾尝试在我的 LINQ 查询结束时调用 .ToList(),因为我收到一条警告,告诉我这样做。但在这种情况下,Input string was not in a correct format 错误是在我的 LINQ 查询中直接引发的,而不是在 names.Count() 调用中引发的。

我确实理解这个错误的性质,当我在 LINQ 查询中调用 uint.Parse(x.Attributes().First(a => a.Name.LocalName == "ID").Value) 时,有些东西没有得到正确的解析,但我不明白为什么有两个原因:

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

  2. 当不使用 names.Count().ToList() 时,虽然当我查看变量时确实提到了调试模式下的错误,但与 [=15= 关联的名称] 仍然找到并且函数 returns 它正确。

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

问题是,当您使用 ElementAt(0) 时,它只需要找到第一个元素 - 所以如果后面有一个 ID 元素具有无效值(我确定有), 你不会击中它。当您调用 Count()ToList() 时,它会遍历查询的 整个 ,从而导致问题。

事实上,您的代码非常低效,需要多次评估 - 最好写成:

public String GetItemName(uint id)
{
    IEnumerable<String> names = ...; // Query as before
    return names.FirstOrDefault() ?? "";
}

我还建议使用 LINQ 提供的显式转换 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 进行比较.