我希望Visual Studio在处理异常发生时中断(即我不只是想看到“第一次机会”消息,我想调试实际的异常)。

例:我希望调试器在异常时中断:

try
{
   System.IO.File.Delete(someFilename);
}
catch (Exception)
{
   //we really don't care at runtime if the file couldn't be deleted
}

我偶然发现了这些Visual Studio的笔记。NET:

1) In VS.NET go to the Debug Menu >> "Exceptions..." >> "Common Language Runtime Exceptions" >> "System" and select "System.NullReferenceException" 2) In the bottom of that dialog there is a "When the exception is thrown:" group box, select "Break into the debugger" 3) Run your scenario. When the exception is thrown, the debugger will stop and notify you with a dialog that says something like: "An exception of type "System.NullReferenceException" has been thrown. [Break] [Continue]" Hit [Break]. This will put you on the line of code that's causing the problem.

但是它们不适用于Visual Studio 2005(在Debug菜单上没有例外选项)。

有人知道在Visual Studio中“当抛出异常时”组框的哪里找到这个选项对话框,其中有“进入调试器”的选项吗?

更新:问题是我的调试菜单没有异常项。我自定义菜单手动添加它。


当前回答

我使用的一种技巧如下所示。定义一个全局变量,可以用于一个或多个try catch块,这取决于你要调试的内容,并使用以下结构:

if(!GlobalTestingBool)
{
   try
   {
      SomeErrorProneMethod();
   }
   catch (...)
   {
      // ... Error handling ...
   }
}
else
{
   SomeErrorProneMethod();
}

我发现这在测试方面给了我更多的灵活性,因为仍然存在一些我不希望IDE中断的异常。

其他回答

还有一些其他方面需要解释。通常,除非发生异常,否则应用程序不应该抛出异常。

微软的文档说:

对于可能发生但可能触发异常的情况,请考虑以避免异常的方式处理它们。

and

类可以提供方法或属性,使您能够避免进行可能触发异常的调用。

异常会降低性能并破坏调试体验,因为您应该能够中断任何正在运行的代码中的所有异常。

如果您发现调试经验很差,因为调试器经常在毫无意义的异常上中断,那么您可能需要在测试中检测已处理的异常。这种技术允许您在代码抛出意外异常时失败测试。

这里有一些辅助函数

public class HandledExceptionGuard
{
    public static void DoesntThrowException(Action test,
      Func<object?, Exception, bool>? ignoreException = null)
    {
        var errors = new List<ExceptionInformation>();

        EventHandler<FirstChanceExceptionEventArgs> handler = (s, e) =>
        {
            if (e.Exception is AssertFailedException) return;
            if (ignoreException?.Invoke(s, e.Exception) ?? false) return;
            errors.Add(new ExceptionInformation(s, e.Exception, AppDomain.CurrentDomain.FriendlyName));
        };

        AppDomain.CurrentDomain.FirstChanceException += handler;

        test();

        AppDomain.CurrentDomain.FirstChanceException -= handler;

        if (errors.Count > 0)
        {
            throw new ExceptionAssertionException(errors);
        }
    }

    public async static Task DoesntThrowExceptionAsync(Func<Task> test,
      Func<object?, Exception, bool>? ignoreException = null)
    {
        var errors = new List<ExceptionInformation>();

        EventHandler<FirstChanceExceptionEventArgs> handler = (s, e) =>
        {
            if (e.Exception is AssertFailedException) return;
            if (ignoreException?.Invoke(s, e.Exception) ?? false) return;
            errors.Add(new ExceptionInformation(s, e.Exception, AppDomain.CurrentDomain.FriendlyName));
        };

        AppDomain.CurrentDomain.FirstChanceException += handler;

        await test();

        AppDomain.CurrentDomain.FirstChanceException -= handler;

        if (errors.Count > 0)
        {
            throw new ExceptionAssertionException(errors);
        }
    }
}

如果在这些方法中包装如下所示的任何代码,当发生已处理的异常时,测试将失败。你可以忽略回调的异常。这将针对不想要的已处理异常验证您的代码。

[TestClass]
public class HandledExceptionTests
{
    private static void SyncMethod()
    {
        try
        {
            throw new Exception();
        }
        catch (Exception)
        {

        }
    }

    private static async Task AsyncMethod()
    {
        try
        {
            await Task.Run(() => throw new Exception());
        }
        catch (Exception)
        {

        }
    }

    [TestMethod]
    public void SynchronousTest()
    {
        HandledExceptionGuard.DoesntThrowException(() => SyncMethod());
    }

    [TestMethod]
    public async Task AsyncTest()
    {
        await HandledExceptionGuard.DoesntThrowExceptionAsync(() => AsyncMethod());
    }
}

我使用的一种技巧如下所示。定义一个全局变量,可以用于一个或多个try catch块,这取决于你要调试的内容,并使用以下结构:

if(!GlobalTestingBool)
{
   try
   {
      SomeErrorProneMethod();
   }
   catch (...)
   {
      // ... Error handling ...
   }
}
else
{
   SomeErrorProneMethod();
}

我发现这在测试方面给了我更多的灵活性,因为仍然存在一些我不希望IDE中断的异常。

打开解决方案后,转到调试- Windows -异常设置(Ctrl+Alt+E)菜单选项。从那里你可以选择中断抛出的或用户未处理的异常。

编辑:我的实例是用c#“配置文件”设置的,也许它没有其他配置文件?

我花了一段时间才找到期望设置的新地方,因此有了一个新的答案。

自Visual Studio 2015以来,您可以在异常设置窗口(调试->Windows->异常设置)中控制要停止的异常。快捷键仍然是Ctrl-Alt-E。

处理自定义异常的最简单方法是选择“不在此列表中的所有异常”。

以下是英文版的截图:

以下是德国版的截图:

VS2005中有一个“例外”窗口…调试时尝试按Ctrl+Alt+E,并单击要停止的异常的“抛出”复选框。