【问题标题】:Strange unhandled XmlException behaviour奇怪的未处理 XmlException 行为
【发布时间】:2009-09-10 11:34:46
【问题描述】:

在阅读 this recent question 关于未处理的 XmlException 时,我尝试在 .NET 2.0 和 3.5 控制台应用程序中重现它。

但是在我的代码中,它的行为完全符合预期,XmlDocument.Load 方法会引发 XmlException,因为源 xml 文件包含 NULL 字符。

那么,为什么以下代码(来自该示例)中的 Load 语句不抛出 XmlException?更重要的是,为什么围绕 SelectNodes() 方法调用的有效 try 块没有处理 XmlException?

虽然我猜测内部可能会发生某种延迟加载/缓存,但这种行为是不是非常不直观和令人困惑?

(前面的问题清楚地显示了调试器的屏幕截图,它抱怨 SelectNodes() 抛出了 XmlException 但未处理???)

    XmlDocument xDoc = new XmlDocument();
    xDoc.Load(File.FullName);

    //work through each print batch in this queue file
    try
    {
        // This line throws an XmlException but is not handled by the catch!
        XmlNodeList nodeList = xDoc.SelectNodes("Reports/PrintBatch");

        foreach (XmlNode printBatch in nodeList)//xDoc.SelectNodes("Reports/PrintBatch"))
        {
            PrintBatch batch = new PrintBatch();
            batch.LoadBatch(printBatch, File.Extension);
            this.AddBatch(batch);
        }
    }
    catch (XmlException e)
    {
        //this report had an error loading!
        Console.WriteLine(e.Message);
    }

【问题讨论】:

    标签: c# xml exception


    【解决方案1】:

    XmlDocument.Load 总是按预期抛出异常。

    只是有时调试器会弄错行号。以我的经验,下一行代码被错误地突出显示为异常的抛出者并不少见。

    您可以在屏幕截图中看到这一点:ASP 错误页面正确显示 XmlDocument.Load 是 thrower,而不是 SelectNodes 语句。

    【讨论】:

    • 你看起来是对的。我检查了 Reflector 中 Load 和 SelectNodes 的实现,它只显示 Load 调用 XmlLoader.LoadNode() (如堆栈跟踪所示)。因此调试符号可能与显示的代码不同步。
    【解决方案2】:

    您得到异常而他没有得到异常的原因可能有很多,这很可能与 NULL 字符的位置有关。根据他的堆栈,他的 Null 字符似乎位于 XML 的末尾,位置为 115227。可能是它之前的文本只是有效的 XML,并且在文件末尾意外添加了一个额外的 NULL 字符.你的 NULL 字符在哪里?

    或者,他的 NULL 字符位于属性或元素内,并被视为文本的一部分。它还可能取决于 XML 是 UTF-8、UTF-16 还是其他编码类型。需要考虑的变量太多。


    当 NULL 字符在末尾时,整个文件恰好是一个很好的、以空字符结尾的字符串。尽管如此,正如您所说,当它在 try-except 块内时被认为是未处理的异常,这很奇怪......

    有一些 interesting reading here 关于捕获未处理的异常,但它没有解释它们为什么会发生。

    但如果我不得不猜测... XML 类的后面有一堆非托管代码。由于 NULL 字符,此非托管代码会变得混乱,并在发布时会产生错误。对 SelectNodes() 的调用将触发验证并发现错误,因此会引发错误。系统开始处理异常处理程序,但它首先尝试释放 xDoc,因为它没有在异常块内部或之后使用。这释放了非托管代码,但非托管代码仍然混乱,因此它再次引发异常。这将阻止 Catch 处理异常。 您可以通过在 Catch 语句之后添加第二个 xDoc.Load() 来测试这一点,这将防止 xDoc 在 Catch 之前被释放。

    不过,这只是一个猜测......对我来说似乎是一个 .NET 错误。

    【讨论】:

    • 在 120K 文件上进行了测试。 XML 中的 NULL 抛出,文档末尾的 NULL 不会导致 Load() 或 SelectNodes() 出现任何问题。但真正的问题是为什么当 SelectNodes() 被调用一个显式处理 XmlException 的 try 块时,XmlException 被认为是未处理的?
    猜你喜欢
    • 1970-01-01
    • 2010-10-12
    • 1970-01-01
    • 1970-01-01
    • 2011-06-16
    • 2017-02-14
    • 2016-05-10
    • 1970-01-01
    • 2021-09-03
    相关资源
    最近更新 更多