Skip to content

perf: enumerate result pages without boxing - #50

Open
msallin wants to merge 1 commit into
evolvedlight:developfrom
swisspost:perf/result-struct-enumerators
Open

perf: enumerate result pages without boxing#50
msallin wants to merge 1 commit into
evolvedlight:developfrom
swisspost:perf/result-struct-enumerators

Conversation

@msallin

@msallin msallin commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

SvgResult and PngResult forwarded GetEnumerator() to the list behind their Pages property, which hands its enumerator back as an IEnumerator<T> and so boxes the struct: 80 bytes per pass over an SVG and a PNG result. A struct enumerator, which foreach binds to in preference to the interface, removes that. Both the foreach path and the interface path go through it, so the two agree.

Adds one public type, PageEnumerator<T>. It cannot be hidden: a public method may not return a less accessible type.

Binary-breaking, and wider than it looks. A return type is part of the method signature and foreach binds to the concrete method, so every already-compiled foreach over a result-typed variable throws MissingMethodException until recompiled, not just code that named IEnumerator<T> itself. Source-compatible; LINQ, Count and the indexer are unaffected. Needs a version bump rather than a patch, and is recorded in RELEASENOTES.

Tests: zero allocations across a pass over both result types, which fails at exactly 80 bytes without the change, plus agreement between the struct path, the indexer and LINQ.

58/58 pass, clean on net8/9/10.

SvgResult and PngResult forwarded GetEnumerator to the list behind their Pages
property, which hands its enumerator back as an IEnumerator<T> and so boxes the
struct: 80 bytes per pass over an SVG and a PNG result. A struct enumerator,
which foreach binds to in preference to the interface, removes that. Both the
foreach path and the interface path go through it, so the two agree on how an
exhausted or not-yet-started enumerator behaves.

Binary-breaking: a return type is part of the method signature and foreach binds
to the concrete method, so an assembly compiled against an earlier version has
to be recompiled. Source-compatible.
@msallin
msallin force-pushed the perf/result-struct-enumerators branch from 28f2ddc to 8cd4ac1 Compare September 6, 2026 19:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant