Replies: 37 comments 2 replies
-
|
Beta Was this translation helpful? Give feedback.
-
Having My use case is performing a test or another operation on each element of an I need to do a workaround with a temp variable like this: Result temp = null;
try
{
temp = new Result(operation(thing));
}
catch(Exception e)
{
temp = new Result(e);
}
yield return temp; Instead of the direct version: try
{
yield return new Result(operation(thing));
}
catch(Exception ex)
{
yield return new Result(ex);
} |
Beta Was this translation helpful? Give feedback.
-
Actually, that makes a lot of sense to me. You should always put as little code as humanly possible inside a In other words, I believe that including (Also you should almost never use a catch-all except as the top-level handler. If you don't know precisely why an exception is being thrown, any kind of corruption may have occurred and continuing operation is dangerous. Failing fast and loud is safe and helpful.) |
Beta Was this translation helpful? Give feedback.
-
I agree that it isn't pretty, but hopefully that discourages common abuses of try-catch. |
Beta Was this translation helpful? Give feedback.
-
This was a greatly simplified example, but it clearly shows the feature disparity between This milder example also doesn't work: try
{
yield return Foo(myThing1, myThing2);
}
catch(VerySpecificException e)
{
// For this method's callers, VerySpecificExceptions coming from Foo are not important,
// but log them for diagnostics
myLogger.LogExpectedException(e);
} |
Beta Was this translation helpful? Give feedback.
-
@jskeet once explained it. (times flies, doesn't it?).
I agree that best practices should not be something on the table. I don't believe that being a bad practice is a valid argument against the development of a language feature. |
Beta Was this translation helpful? Give feedback.
-
The reason for not being able to CodePlex: Anonymous Iterators, Yielding in a Try...Catch Block |
Beta Was this translation helpful? Give feedback.
-
I'm not sure I follow. How is this: try
{
yield return Foo();
}
catch(SomeException e)
{
// handle the exception
} expected to behave differently than this? SomeType temp;
bool ranSuccessfully = false;
try
{
temp = Foo();
ranSuccessfully = true;
}
catch(SomeException e)
{
// handle the exception
}
if(ranSuccessfully)
{
yield return temp;
} |
Beta Was this translation helpful? Give feedback.
-
The argument that the callee can somehow handle exceptions made from its caller is weird, but at least the feature is available in VB, that's good to know. |
Beta Was this translation helpful? Give feedback.
-
The "mental model", as it were, is that the |
Beta Was this translation helpful? Give feedback.
-
That's a weird model. The iterator "calling up" to the enumerator body goes against the syntax as well as the actual implementation. |
Beta Was this translation helpful? Give feedback.
-
@lcsondes No weirder than |
Beta Was this translation helpful? Give feedback.
-
I have actually written production code in PL/SQL that does its local equivalent of |
Beta Was this translation helpful? Give feedback.
-
@jnm2 Sure. Iterators also pretend that you're writing synchronous code, but you're yielding control to your caller. I expected them to behave similarly when it came to exceptions. |
Beta Was this translation helpful? Give feedback.
-
@HaloFour It would never cross my mind to think about it like that. And I can't even imagine trying to explain the semantics of the result to someone. Supporting |
Beta Was this translation helpful? Give feedback.
-
I don't think it's fundamentally different from This code has similar theoretical problems but it already compiles, calling MoveNext and Dispose on it results in 0, 2, 3: try
{
try
{
Write(0);
yield break;
Write(1);
}
finally
{
Write(2);
}
yield break;
}
finally
{
Write(3);
}
yield break; |
Beta Was this translation helpful? Give feedback.
-
Thanks for clarifying your proposal.
Thinking more about my earlier comment, I had the design of async-iterators in mind. Iterators may actually be trickier. Would have to check. |
Beta Was this translation helpful? Give feedback.
-
I've double-checked the behavior of
I can get behind this, but most users would use some variant of |
Beta Was this translation helpful? Give feedback.
-
This is made so much worse with async iteration and using declarations, since the compiler adds a lot more magic that becomes unavailable to you. I have a method of the form IAsyncEnumerator<T> myEnumeration(CancellationToken cancellationToken) {
await using var someAsyncDisposable = ...
await using var someOtherAsyncDisposable = someAsyncDisposable(...);
// etc.
await foreach (var t in myRealEnumeratingThing(cancellationToken)) yield return t;
} But here's the problem: inside the block, any code (both setup and enumeration) may throw a The simple solution of wrapping the whole thing in a And just to head off the discussion: yes, of course the third-party code throwing |
Beta Was this translation helpful? Give feedback.
-
You can |
Beta Was this translation helpful? Give feedback.
-
@gafter They might be asking for |
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
That seems even weirder of a restriction, what issue does a try-yield-catch have that a try-yield-finally does not? (and generally speaking, you can do most of your standard exception handling in iterators anyway as long as they're separated from |
Beta Was this translation helpful? Give feedback.
-
foo() {
using var x = ..
using var y = ..
using var z = .. // use x and y
yield ... // use z
} If an error can happen creating |
Beta Was this translation helpful? Give feedback.
-
Yeah, that's the whole reason I've opened this issue - since C# 6 we know that breaking up methods in catch/finally blocks is in fact not impossible to implement, and most of the work involving the state machine transformation has been done at that time for |
Beta Was this translation helpful? Give feedback.
-
I think that yield inside catch and yield inside finally are 2 different scenarios. In a catch, control is currently inside your own code, and wishing to replace some of your own exceptions when you try'd something with a yield'd object makes sense. In a finally, control is currently in a semi-uncontrolled state, potentially already returning via exception-throw, so for the same reason that "return" in finally doesn't make sense, a yield here doesn't make sense. Implementation wise, i don't beleive it could be harder than having a using around an async, which we already have. knowing we start at -100: in non yielding code we have, and expect behaviour like the following:
adding async stuff doesn't change this mental model
I believe this request would be helpful to avoid switching mental models for error handling on IEnumerables - to me it makes sense that this could/should result in either "thing" or "errorThing" just like the prior two examples.
it would make sense that yield return can be in the same place as return. To me the third example isn't ambiguous, even when understanding how IEnumerable works with the coceptual flow - somebody calls "MoveNext", we call f(), and if I exception then the errorThing is what we get back, the state machine isn't particularly complex IMO. This could be the same as the following ,but with no leakage of the boolean, no issues to do with the early assignment of result to null to avoid the "use of not assigned" error, and minimising the extra code complexity
|
Beta Was this translation helpful? Give feedback.
-
I can get behind not allowing it in I'd like to highlight one thing from your examples though. Unless I'm missing some odd peculiarity of the language spec, if a It looks like we somehow got the more difficult part of this feature with |
Beta Was this translation helpful? Give feedback.
-
many applications (eg, web api's that fetch by block, database queries, csv parsers) .... work by IEnumerable. @lcsondes - would this request include yield in 'try' as well as 'catch' ? |
Beta Was this translation helpful? Give feedback.
-
Now, what's the current state here? Discussion seems to have reached some kind of consent 4 years ago, and then everything fell asleep. :-) We have some iterator which internally loops, and has to handle exceptions (as it should handle the exception and continue looping and yielding, instead of just letting the exception bubble outside). And currently, we have to code around this limitation. |
Beta Was this translation helpful? Give feedback.
-
Got a bit nerd sniped into thinking about this feature earlier this week. Paged enough of the problem space in that I wrote a proposal for it. Appreciate any feedback. |
Beta Was this translation helpful? Give feedback.
-
Since C# 6,
await
is allowed incatch
andfinally
blocks. I would like ifyield return
andyield break
were brought up to parity and permitted intry
,catch
,and finallyblocks.Edit: After detailed discussion (thank you everyone!) it seems that the
finally
case would just cause more trouble and confusion than it's worth, however thecatch
seems straightforward, and it would also match regularreturn
perfectly.Beta Was this translation helpful? Give feedback.
All reactions