如何在C#中的yield return方法中正确抛出Exception

Fra*_*yce 8 c# exception yield-return

请参阅下面的编辑,以重现我在此问题中描述的行为.

以下程序永远不会结束,因为yield returnC#中的构造在GetStrings()抛出异常时无限期地调用该方法.

class Program
{
    static void Main(string[] args)
    {
        // I expect the Exception to be thrown here, but it's not
        foreach (var str in GetStrings())
        {
            Console.WriteLine(str);
        }
    }

    private static IEnumerable<string> GetStrings()
    {
        // REPEATEDLY throws this exception
        throw new Exception();
        yield break;
    }
}
Run Code Online (Sandbox Code Playgroud)

对于这个简单的例子,我显然可以使用return Enumerable.Empty<string>();,而问题就消失了.但是在一个更有趣的例子中,我希望抛出异常一次,然后调用方法停止并在"消耗"的方法中抛出异常IEnumerable.

有没有办法产生这种行为?

编辑:好的,问题与我的想法不同.上面的程序没有结束,foreach循环表现得像一个无限循环.以下程序将结束,并在控制台上显示异常.

class Program
{
    static void Main(string[] args)
    {
        try
        {
            foreach (var str in GetStrings())
            {
                Console.WriteLine(str);
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
        }
    }

    private static IEnumerable<string> GetStrings()
    {
        throw new Exception();
        yield break;
    }
}
Run Code Online (Sandbox Code Playgroud)

为什么try... catch块会在这种情况下产生影响?这对我来说似乎很奇怪.感谢@AndrewKilburn的回答已经指向我.

编辑#2:从命令提示符开始,程序在两种情况下都执行相同的操作.在Visual Studio Enterprise 2015 Update 2中,无论是在Debug还是Release中编译,上面的行为就是我所看到的.使用try... catch,程序以异常结束,没有它,Visual Studio永远不会关闭程序.

编辑#3:固定对我来说,问题是由@MartinBrown的答案解决的.当我在"调试">"选项">"调试">"常规">"解除对未处理的异常的调用堆栈"下取消选中Visual Studio的选项时,此问题就会消失.当我再次检查该框时,问题又回来了.

Mar*_*own 7

这里看到的行为不是代码中的错误; 相反,它是Visual Studio调试器的副作用.这可以通过在Visual Studio中关闭堆栈展开来解决.尝试进入Visual Studio选项Debugging/General并取消选中"在未处理的异常上展开调用堆栈".然后再次运行代码.

当您的代码遇到完全未处理的异常时,Visual Studio会将调用堆栈展开到代码中导致异常的行之前.它这样做是为了您可以编辑代码并继续执行编辑的代码.

这里看到的问题看起来像是一个无限循环,因为当您在调试器中重新开始执行时,下一行要运行的是刚引起异常的那一行.在调试器之外,调用堆栈将在未处理的异常上完全展开,因此不会导致您在调试器中获得相同的循环.

可以在设置中关闭此堆栈展开功能,默认情况下启用它.然而,将其关闭将阻止您编辑代码并继续,而无需先自行展开堆栈.但是,从调用堆栈窗口或从Exception Assistant中选择"启用编辑",这很容易.

  • @MatteoUmili关于这个问题的一些阅读,我已经填写了一些答案. (2认同)
  • @Mike看来,是的,它已经在VS2017中消失了.:(见Hans Passant对这个问题的评论:/sf/ask/3018829831/ (2认同)