refactor(binder): extract shared list-element iteration - #184
Merged
Conversation
The three list converters (simple, simple-value, complex) each carried an identical element loop: indexed iteration, a null element recorded as REQUEST_ARGUMENT_REQUIRED, collect every successful element, and return a RequiredField. Factor that shared invariant into a single RequestBinder.ConvertEachElement primitive so the iteration and the null-element rule live in one place; each converter now supplies only its per-element convert/bind and failure recording through a callback. No behavior change; the public binder surface is unchanged. Refs: #150 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J12ghrzM1xiAKw4LETJDqr
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The three list converters each carried an identical element loop. This factors that shared iteration into a single internal
RequestBinder.ConvertEachElementprimitive, so the loop and the null-element rule live in one place. No behavior change, no public API change.Type of change
Changes
internal RequestBinder<TRequest>.ConvertEachElement<TStored, TProperty>(...): indexed iteration over the stored list elements, anullelement recorded asREQUEST_ARGUMENT_REQUIRED, every successful element collected (one bad element never hides the others), and the boundRequiredFieldreturned. It is generic over the stored element type (TStored) soelement is nullnarrows uniformly for both reference elements andNullable<T>elements — avoiding the type-kind wall that forced the value-type list converter to be separate.ListOfSimplePropertiesConverter.ConvertElementsnow delegates to the primitive, supplying only its per-element convert +RecordArgumentInvalid.ListOfSimpleValuePropertiesConverter.ConvertElementslikewise, supplying theNullable<T>unwrap (element.Value) +RecordArgumentInvalid.ListOfComplexPropertiesConverter.BindElementslikewise, supplying the nested binder +NestedFailure.Groupwrapping.Net effect: the triplicated iteration/index/null-element/collect logic is removed (+52 / −70).
Testing
dotnet build FirstClassErrors.sln— 0 warnings, 0 errorsdotnet test FirstClassErrors.sln— 1000 tests, 0 failuresFirstClassErrors.Analyzers.UnitTests)Documentation
Architecture decisions
Related issues
Closes #150
Generated by Claude Code