Skip to content

avoid some redundant enumerable alloc#4972

Open
SimonCropp wants to merge 3 commits intothomhurst:mainfrom
SimonCropp:avoid-some-redudnant-enumerable-alloc
Open

avoid some redundant enumerable alloc#4972
SimonCropp wants to merge 3 commits intothomhurst:mainfrom
SimonCropp:avoid-some-redudnant-enumerable-alloc

Conversation

@SimonCropp
Copy link
Contributor

No description provided.

Copy link
Contributor

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This is a clean, well-targeted optimization. Eliminating the async/yield return wrappers that were purely forwarding elements is exactly the right call.

Why this is correct

Each async IAsyncEnumerable method backed by a yield return causes the C# compiler to generate a state machine class. When the wrapper does nothing but forward items, you're allocating that state machine per call for zero benefit. Returning the inner IAsyncEnumerable<T> directly is semantically equivalent here and avoids the allocation entirely — consistent with the project's "Performance First" mandate.

There's one subtle behavioral difference worth being aware of: in the old wrapper form, any synchronous exception thrown inside GenerateDataSourcesAsync before its first MoveNextAsync would be deferred to the enumeration phase. With the direct return, such an exception propagates immediately to the caller. In practice this is a non-issue here — GenerateDataSourcesAsync is itself an async iterator in derived classes and won't throw synchronously before returning the IAsyncEnumerable — but it's worth noting for future changes.

AOT benefit

Fewer compiler-generated state machine types also reduces the AOT codegen surface, which aligns well with TUnit's Native AOT compatibility requirement.

Minor observation (out of scope for this PR)

After this change in AsyncUntypedDataSourceSourceGeneratorAttribute, the call chain is:

GetDataRowsAsync → GenerateAsync → GenerateDataSourcesAsync

GenerateAsync is now a pure pass-through. GetDataRowsAsync could call GenerateDataSourcesAsync directly, but that's a separate refactor and the current structure is fine as-is.

The removed comment in AsyncUntypedDataSourceSourceGeneratorAttribute.cs was only documenting intent in the now-deleted loop body, so removing it is appropriate.

Overall: LGTM. Straightforward, correct, and beneficial to performance and AOT compatibility.

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