避免在异常已经安全处理时出现第一次机会异常消息

78
以下代码片段捕捉 EOS 异常。
using (var reader = new BinaryReader(httpRequestBodyStream)) {

    try {
        while (true) {
            bodyByteList.Add(reader.ReadByte());
        }
    } catch (EndOfStreamException) { }
}

那么为什么我的控制台仍然会收到“first-chance exceptions”?

在mscorlib.dll中发生了类型为'System.IO.EndOfStreamException'的一次 first chance exception。

有没有办法隐藏这些 first chance exception 消息?

9个回答

190
为了避免看到消息,右键单击输出窗口并取消选中“异常消息”。
然而,如果你对未设置断点和重新配置调试器时抛出异常的情况感兴趣,看到它们发生可能是不错的。

79

"第一次机会"异常的目的是,您可以在抛出时在调试期间停止它们,以便您可以在处理程序之前看到它们。 "第二次机会"异常是没有适当处理程序的异常。有时您想捕获“第一次机会”异常,因为重要的是要看到当它被抛出时正在发生什么,即使有人已经捕获了它。

这是正常行为,无需担心。


58
确实,这个问题并不需要过多关注,但它会使调试输出日志变得混乱。:( - Dimitri C.

20
  1. 在 Visual Studio 中,您可以更改调试器处理(中断)异常的方式的设置。

    前往“调试”>“异常”。(请注意,这可能不在您的菜单中,这取决于您的 Visual Studio 环境设置。如果没有,请使用“自定义”菜单将其添加到菜单中。)

    在那里,您会看到一个对话框,其中包含异常及何时中断它们的信息。

    在“公共语言运行时异常”一行中,您可以取消选中已抛出的异常(这样应该就不会再打扰您了)并且如果您需要的话还可以取消选中未处理用户异常(但我不建议这么做)。

  2. 您看到的消息不应该出现在控制台中,而应该出现在 Visual Studio 的“输出”窗口中。如果是这种情况,那么我就没有找到去除它的可能性,但是如果您在没有 Visual Studio 的情况下运行应用程序,则不会出现该消息。


12

与Java不同,.NET异常在处理能力方面相当昂贵,在正常和成功的执行路径中应避免处理异常。

这样不仅可以避免控制台窗口混乱,而且可以提高性能,并使.NET CLR异常等性能计数器更有意义。

在这个例子中,您将使用

while (reader.PeekChar() != -1)
{
    bodyByteList.Add(reader.ReadByte());
}

1
你可以使用ReadBytes一次性获取所有字节,并利用缓冲区。但我想那不是问题的关键。 - Craig Tyler
9
没问题。 "有没有一种方法可以隐藏这些一次性异常消息?" -使用这个循环,首次机会异常不会出现。 :) - loudej

7

我曾经遇到这个问题,但无法确定异常是在哪里抛出的。我的解决方案是让Visual Studio停止执行此类异常。

  1. 导航到“调试/异常”
  2. 展开“公共语言运行时异常”树形结构。
  3. 展开“系统”分支。
  4. 向下滚动到“NullReferenceException”的位置,并选中“throw”复选框,取消选中“user-handled”。
  5. 调试您的项目。

5
如果您想更好地控制这些消息,可以添加一个处理程序:
Friend Sub AddTheHandler()
AddHandler AppDomain.CurrentDomain.FirstChanceException, AddressOf FirstChanceExceptionHandler
End Sub

<Conditional("DEBUG")>
Friend Sub FirstChanceExceptionHandler( source As Object,  e As Runtime.ExceptionServices.FirstChanceExceptionEventArgs)
' Process first chance exception

End Sub

这使你可以像其他评论中提到的那样将它们静音,但仍确保你能够意识到它们。如果我记录一个消息和时间戳到文本文件中,我发现看到我实际抛出了多少是很好的。


1
好的建议。但值得注意的是,System.Runtime.ExceptionServices 仅适用于 .Net 4.0 或更高版本。对于我们这些处理针对 .Net 3.5(或更早版本)编写的遗留代码的人来说,这可能不可行。 - paulsm4
这适用于 ASP.NET 吗? - Kiquenet
1
多亏了这段代码,你再也不需要使用Visual Studio内置的输出面板来报告异常了,可以将其关闭(右键单击输出面板并取消“异常消息”复选框)。这段代码将自行报告异常(例如,使用Debug.WriteLine($"Exception thrown: '{e.Exception.GetType().FullName}' in {e.Exception.Source}");),它还可以进行一些过滤,因此不会强制报告所有异常。 - Roland Pihlakas

2

实际上,如果每秒有很多异常,通过检查reader.EndOfStream-value可以获得更好的性能。打印这些异常消息非常慢,而在Visual Studio中隐藏它们并不会加快任何速度。


-1

在VB.NET中:

<DebuggerHidden()> _
Public Function Write(ByVal Text As String) As Boolean
   ...

1
这与问题无关。 - John Saunders
实际上,使用 [DebuggerNonUserCode] 确实隐藏了“第一次机会异常”消息。我不会感到惊讶如果 DebuggerHidden 也能做到这一点。 - Ruben
我不确定这些是否被视为异常,但是[DebuggerNonUserCode]不会隐藏任何“托管调试助手”。例如,当我使用XmlSerializer时,我会遇到BindingFailures,除了在异常对话框中取消选中抛出BindingFailure之外,我还没有找到其他方法来隐藏它。 - Anthony Brien
1
似乎使用 DebuggerHiddenAttribute 只是意味着第一次机会异常将显示在调用方法上,而不是方法本身。 - Thorarin

-4

我认为流正在抛出这个异常,所以你的try作用域太窄了,无法捕获它。

在不同的作用域周围添加更多的try catch组合,直到你在实际抛出异常的地方捕获它,但似乎它发生在你的using之外或之内,因为流对象并没有在using的作用域中创建。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接