The following is okay:
try { Console.WriteLine("Before"); yield return 1; Console.WriteLine("After"); } finally { Console.WriteLine("Done"); }
The finally
block runs when the whole thing has finished executing (IEnumerator<T>
supports IDisposable
to provide a way to ensure this even when the enumeration is abandoned before it finishes).
But this is not okay:
try { Console.WriteLine("Before"); yield return 1; // error CS1626: Cannot yield a value in the body of a try block with a catch clause Console.WriteLine("After"); } catch (Exception e) { Console.WriteLine(e.Message); }
Suppose (for the sake of argument) that an exception is thrown by one or other of the WriteLine
calls inside the try block. What's the problem with continuing the execution in catch
block?
Of course, the yield return part is (currently) unable to throw anything, but why should that stop us from having an enclosing try
/catch
to deal with exceptions thrown before or after a yield return
?
Update: There's an interesting comment from Eric Lippert here - seems that they already have enough problems implementing the try/finally behaviour correctly!
EDIT: The MSDN page on this error is: http://msdn.microsoft.com/en-us/library/cs1x15az.aspx. It doesn't explain why, though.
No, it's not a bad practice. Putting return where it makes sense improves readability and maintainability and makes your code simpler to understand.
you can use a return statement inside the try block, but you have to place another return outside the try block as well. If you pass true while calling sayHello method, it would return from try block. A return statement has to be at the method level instead of at any other specific level.
Return statement in catch will be executed only if the catch block is reached, i.e. if there is an error thrown. example() will return 2 since an error was thrown before return 1 . But if there is a finally block and this finally block has a return statement then this return will override catch return statement.
catch: The catch block is used to handle the uncertain condition of a try block. A try block is always followed by a catch block, which handles the exception that occurs in the associated try block.
I suspect this is a matter of practicality rather than feasibility. I suspect there are very, very few times where this restriction is actually an issue that can't be worked around - but the added complexity in the compiler would be very significant.
There are a few things like this that I've already encountered:
In each of these cases it would be possible to gain a little bit more freedom, at the cost of extra complexity in the compiler. The team made the pragmatic choice, for which I applaud them - I'd rather have a slightly more restrictive language with a 99.9% accurate compiler (yes, there are bugs; I ran into one on SO just the other day) than a more flexible language which couldn't compile correctly.
EDIT: Here's a pseudo-proof of how it why it's feasible.
Consider that:
Now transform:
try { Console.WriteLine("a"); yield return 10; Console.WriteLine("b"); } catch (Something e) { Console.WriteLine("Catch block"); } Console.WriteLine("Post");
into (sort of pseudo-code):
case just_before_try_state: try { Console.WriteLine("a"); } catch (Something e) { CatchBlock(); goto case post; } __current = 10; return true; case just_after_yield_return: try { Console.WriteLine("b"); } catch (Something e) { CatchBlock(); } goto case post; case post; Console.WriteLine("Post"); void CatchBlock() { Console.WriteLine("Catch block"); }
The only duplication is in setting up try/catch blocks - but that's something the compiler can certainly do.
I may well have missed something here - if so, please let me know!
All the yield
statements in an iterator definition are converted to a state in a state machine which effectively uses a switch
statement to advance states. If it did generate code for yield
statements in a try/catch it would have to duplicate everything in the try
block for each yield
statement while excluding every other yield
statement for that block. This isn't always possible, particularly if one yield
statement is dependant on an earlier one.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With