- Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
Background and motivation
ConfigureAwaitOptions were added in .NET 8 and the original motivation was to allow await to avoid throwing an exception. This is a niche performance feature and I don't see it got much adoption in codebases outside .NET ecosystem itself. Event I myself am not used to this no-throwing pattern enough, so I may get a spark of realization a few days after the original work is done. Hence I believe there can be an analyzer suggesting to replace most common suppress exceptions patterns with this new option. Not only does this improve perf but also reduce nesting since try is a one nesting level + catch may add another one
API Proposal
Add an analyzer + code fix to suggest replacing suppress exceptions pattern for single await operation with ConfigureAwaitOptions.SuppressThrowing. Concrete example in the section below.
API Usage
- Basic suppress throw:
// Before try { await someExpressionReturinngTask; // or `await someExpressionReturinngTask.ConfigureAwait(true)` } catch // or `catch (Exception)` or `catch (Exception ex)` { } // After await someExpressionReturinngTask.ConfigureAwait(ConfigureAwaitOptions.ContinueOnCapturedContext | ConfigureAwaitOptions.SuppressThrowing);- With
ConfigureAwait(false):
// Before try { await someExpressionReturinngTask.ConfigureAwait(false); } catch { } // After await someExpressionReturinngTask.ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing);- When expression returns
Task<T>, but the result is ignored:
// Before try { await someExpressionReturinngTaskOfT; // or `_ = await someExpressionReturinngTaskOfT` } catch { } // After await ((Task)someExpressionReturinngTaskOfT).ConfigureAwait(ConfigureAwaitOptions.ContinueOnCapturedContext | ConfigureAwaitOptions.SuppressThrowing);- When code inside
catchdoes not depend on caught exception object:
// Before bool hasErrors = false; try { await someExpressionReturinngTask; } catch { hasErrors = true; } // After var someExpressionTask = someExpressionReturinngTask; await someExpressionTask.ConfigureAwait(ConfigureAwaitOptions.ContinueOnCapturedContext | ConfigureAwaitOptions.SuppressThrowing); bool hasErrors = !someExpressionTask.IsCompletedSuccessfully;// Before try { await someExpressionReturinngTask; } catch { Console.WriteLine("This code does not depend on exception object"); } // After var someExpressionTask = someExpressionReturinngTask; await someExpressionTask.ConfigureAwait(ConfigureAwaitOptions.ContinueOnCapturedContext | ConfigureAwaitOptions.SuppressThrowing); if (!someExpressionTask.IsCompletedSuccessfully) { Console.WriteLine("This code does not depend on exception object"); }And any combinatorial combination of these cases.
Alternative Designs
No response
Risks
No response