-
Notifications
You must be signed in to change notification settings - Fork 10.3k
Introduce the Results<TResult1, TResult2, TResultN> union types #40986
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Contributes to #40672
- Add new API to PublicAPIUnshipped.txt - Suppress API baseline in code gen tool - Add code gen tool to the HttpAbstractsions.slnf file
- Added README.md explaining ResultsOfT code generator tool - Added comment to top of ResultsOfT.cs pointing to code generator tool - Updated Http\README.md to include Http.Results
Also added a sample
Is not possible (or make sense) use a T4 template instead of introduce a new project to generate the code? |
I think to date the repo has used console apps for code generation in numerous places (Kestrel, Developer Exception Page, etc.) so I followed that pattern. I'm not super fussed other than it would mean more work to convert what I've done in this PR to use T4 instead, but there'll still be a mix in the repo. |
|
||
``` | ||
dotnet run | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we also add a test that fails if the generator and generated code get out of sync like Kestrel's GeneratedCodeIsUpToDate test?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
writer.WriteIndentedLine("public async Task ExecuteAsync(HttpContext httpContext)"); | ||
writer.WriteIndentedLine("{"); | ||
writer.WriteIndentedLine(2, "ArgumentNullException.ThrowIfNull(httpContext, nameof(httpContext));"); | ||
writer.WriteLine(); | ||
writer.WriteIndentedLine(2, "if (Result is null)"); | ||
writer.WriteIndentedLine(2, "{"); | ||
writer.WriteIndentedLine(3, "throw new InvalidOperationException(\"The IResult assigned to the Result property must not be null.\");"); | ||
writer.WriteIndentedLine(2, "}"); | ||
writer.WriteLine(); | ||
writer.WriteIndentedLine(2, "await Result.ExecuteAsync(httpContext);"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
writer.WriteIndentedLine("public async Task ExecuteAsync(HttpContext httpContext)"); | |
writer.WriteIndentedLine("{"); | |
writer.WriteIndentedLine(2, "ArgumentNullException.ThrowIfNull(httpContext, nameof(httpContext));"); | |
writer.WriteLine(); | |
writer.WriteIndentedLine(2, "if (Result is null)"); | |
writer.WriteIndentedLine(2, "{"); | |
writer.WriteIndentedLine(3, "throw new InvalidOperationException(\"The IResult assigned to the Result property must not be null.\");"); | |
writer.WriteIndentedLine(2, "}"); | |
writer.WriteLine(); | |
writer.WriteIndentedLine(2, "await Result.ExecuteAsync(httpContext);"); | |
writer.WriteIndentedLine("public Task ExecuteAsync(HttpContext httpContext)"); | |
writer.WriteIndentedLine("{"); | |
writer.WriteIndentedLine(2, "ArgumentNullException.ThrowIfNull(httpContext, nameof(httpContext));"); | |
writer.WriteLine(); | |
writer.WriteIndentedLine(2, "if (Result is null)"); | |
writer.WriteIndentedLine(2, "{"); | |
writer.WriteIndentedLine(3, "throw new InvalidOperationException(\"The IResult assigned to the Result property must not be null.\");"); | |
writer.WriteIndentedLine(2, "}"); | |
writer.WriteLine(); | |
writer.WriteIndentedLine(2, "return Result.ExecuteAsync(httpContext);"); |
It's a little bit more efficient if we skip the tail await at the small cost of losing the stack frame if there are any exceptions.
This PR introduces just the
Results<TResult1, TResult2, TResultN>
union types themselves. The types are code generated via a tool, along with their unit tests.When #40646 lands we can update the in-box
IResult
implementations to describe themselves via emitted metdata, and update theResults<TResult1, TResult2, TResultN>
union types to pass through that metadata from theTResultN
type args, along with introducing the newResults.Typed
factory methods for creating results and preserving the concrete types.Until then, the union types allow all the possible
IResult
return types of a route handler delegate to be declared explicitly and thus checked at compile for type safety, e.g.:Fixes #40672