Skip to content

feat(stages)!: swap StageDelegate for IContinuation, resolve lazily - #3

Merged
illia1f merged 1 commit into
mainfrom
feat/stage-continuation-and-lazy-chain
Aug 2, 2026
Merged

feat(stages)!: swap StageDelegate for IContinuation, resolve lazily#3
illia1f merged 1 commit into
mainfrom
feat/stage-continuation-and-lazy-chain

Conversation

@illia1f

@illia1f illia1f commented Aug 2, 2026

Copy link
Copy Markdown
Owner

An interface can grow an InvokeAsync overload that takes arguments. A delegate signature cannot, not without breaking every stage that exists.

Each level now resolves from the container the first time it runs, the handler included, so a stage that short-circuits never builds what sits below it. A container failure comes out of the next.InvokeAsync() call that reached the broken level, where the stages around it can catch it.

A dispatch through N stages allocates N objects instead of 2N+1. The per-level delegate and the per-dispatch stage array are both gone, and a repeated next call allocates nothing. Three stages cost 192 bytes on net10.0 against 416 before.

The broken-contract failures throw HandlerNullTaskException, StageNullTaskException, and OverlappingNextCallException instead of a plain InvalidOperationException. Each carries the type at fault in a property. The two null-task types share an abstract NullTaskException base, so one catch clause covers both.

BREAKING CHANGE: StageDelegate and StageDelegate are removed. A stage takes IContinuation or IContinuation and calls next.InvokeAsync() where it called next().

An interface can grow an InvokeAsync overload that takes arguments. A
delegate signature cannot, not without breaking every stage that exists.

Each level now resolves from the container the first time it runs, the
handler included, so a stage that short-circuits never builds what sits
below it. A container failure comes out of the next.InvokeAsync() call
that reached the broken level, where the stages around it can catch it.

A dispatch through N stages allocates N objects instead of 2N+1. The
per-level delegate and the per-dispatch stage array are both gone, and a
repeated next call allocates nothing. Three stages cost 192 bytes on
net10.0 against 416 before.

The broken-contract failures throw HandlerNullTaskException,
StageNullTaskException, and OverlappingNextCallException instead of a
plain InvalidOperationException. Each carries the type at fault in a
property. The two null-task types share an abstract NullTaskException
base, so one catch clause covers both.

BREAKING CHANGE: StageDelegate<TResponse> and StageDelegate are removed.
A stage takes IContinuation<TResponse> or IContinuation and calls
next.InvokeAsync() where it called next().
@illia1f
illia1f merged commit f2f0eba into main Aug 2, 2026
1 check passed
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