Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly throw an Exception inside yield return method in C#

See edits below for reproducing the behavior that I describe in this problem.

The following program will never end, because the yield return construct in C# calls the GetStrings() method indefinitely when an exception is thrown.

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;
    }
}

For this trivial example, I could obviously use return Enumerable.Empty<string>(); instead, and the problem goes away. However in a more interesting example, I'd expect the exception to be thrown once, then have the method stop being called and throw the exception in the method that's "consuming" the IEnumerable.

Is there a way to produce this behavior?

EDIT: ok, the problem is different than I first thought. The program above does NOT end, and the foreach loop behaves like an infinite loop. The program below DOES end, and the exception is displayed on the console.

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;
    }
}

Why does the try ... catch block make a difference in this case? This seems very strange to me. Thanks to @AndrewKilburn for his answer already for pointing me to this.

EDIT #2: From a Command Prompt, the program executes the same in both cases. In Visual Studio Enterprise 2015, Update 2, whether I compile in Debug or Release, the behavior above is what I am seeing. With the try ... catch, the program ends with an exception, and without it Visual Studio never closes the program.

EDIT #3: Fixed For me, the issue was resolved by the answer by @MartinBrown. When I uncheck Visual Studio's option under Debug > Options > Debugging > General > "Unwind the call stack on unhandled exceptions" this problem goes away. When I check the box again, then the problem comes back.

like image 813
Frank Bryce Avatar asked Jul 07 '16 15:07

Frank Bryce


People also ask

How do you return after throwing an exception?

After throwing an exception, you do not need to return because throw returns for you. Throwing will bubble up the call stack to the next exception handler so returning is not required.

Does throwing exception return?

If you return something from inside a finally block, it still gets returned despite the exception being thrown.

Does yield break return null?

"yield break" breaks the Coroutine (it's similar as "return"). "yield return null" means that Unity will wait the next frame to finish the current scope. "yield return new" is similar to "yield return null" but this is used to call another coroutine.

When should a method throw an exception?

In short: You should throw an exception if a method is not able to do the task it is supposed to do.


2 Answers

The behaviour being seen here is not a fault in the code; rather it is a side effect of the Visual Studio debugger. This can be resolved by turning off stack unwinding in Visual Studio. Try going into Visual Studio options Debugging/General and unchecking "Unwind the call stack on unhandled exceptions". Then run the code again.

What happens is that when your code hits a completely unhandled exception Visual Studio is unwinding the call stack to just before the line in your code that caused the exception. It does this so that you can edit the code and continue execution with the edited code.

The issue seen here looks like an infinite loop because when you re-start execution in the debugger the next line to run is the one that just caused an exception. Outside the debugger the call stack would be completely unwound on an unhandled exception and thus would not cause the same loop that you get in the debugger.

This stack unwinding feature can be turned off in the settings, it is enabled by default. Turning it off however will stop you being able to edit code and continue without first unwinding the stack yourself. This however is quite easy to do either from the call stack window or by simply selecting 'Enable Editing' from the Exception Assistant.

like image 151
Martin Brown Avatar answered Oct 24 '22 13:10

Martin Brown


The following program will never end

That's false. The program is going to end quite quickly.

because the yield return construct in C# calls the GetStrings() method indefinitely when an exception is thrown.

This is false. It doesn't do this at all.

I'd expect the exception to be thrown once, then have the method stop being called and throw the exception in the method that's "consuming" the IEnumerable.

That's exactly what does happen.

Is there a way to produce this behavior?

Use the code you already provided.

like image 30
Servy Avatar answered Oct 24 '22 11:10

Servy