Skip to content

Fix README allocation claims: V3.1 rename + IValueSender alloc-free correction#58

Merged
zachsaw merged 4 commits intomainfrom
copilot/refactor-cast-to-unsafe-as
Mar 6, 2026
Merged

Fix README allocation claims: V3.1 rename + IValueSender alloc-free correction#58
zachsaw merged 4 commits intomainfrom
copilot/refactor-cast-to-unsafe-as

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 28, 2026

The README incorrectly labeled the new ValueTask features as "V4" (non-breaking, so V3.1) and contained a stale note claiming IValueSender.Send still had boxing overhead — the opposite of what the Unsafe.As change achieved.

Changes

  • Version label: What's New in V4What's New in V3.1 throughout (ToC, heading, body)
  • Allocation table: IValueSender.Send row updated from "Reduced allocation" → "Zero allocation — fully alloc-free in the mediator infrastructure"
  • Note: Rewrites the allocation explanation to be accurate:
    • IValueSender.Send + IValueRequestHandler (no behaviors): fully alloc-free — Unsafe.As reinterpret, struct ValueTask<TResponse> return, non-async generated Handle_Xxx method, nothing heap-allocates
    • IValuePublisher.Publish: same zero-cost dictionary routing, but the generated notification fan-out uses async iteration, which may allocate when handlers are genuinely asynchronous — "dispatch layer" qualifier retained for this row
Path Before After
IValueSender.Send + IValueRequestHandler Reduced allocation / "still has boxing overhead" Zero allocation — fully alloc-free
IValuePublisher.Publish + IValueNotificationHandler Zero allocation in dispatch layer Zero allocation in dispatch layer (unchanged, accurate)
Original prompt

In the CodeGenerator.cs file, specifically within the Send and IValueSender.Send method implementations, replace the standard casts with Unsafe.As to avoid redundant type checks and boxing for ValueTask return types.

Currently, the generated mediator has dictionary lookup as follows:

if (TaskSendSwitchCase.Cases.TryGetValue(request.GetType(), out var handle))
{
    return (global::System.Threading.Tasks.Task<TResponse>)handle(this, request, cancellationToken);
}

And for ValueTask:

if (ValueSendSwitchCase.Cases.TryGetValue(request.GetType(), out var handle))
{
    return (global::System.Threading.Tasks.ValueTask<TResponse>)handle(this, request, cancellationToken);
}

The dictionary value type is Func<{{className}}, object, CancellationToken, object>.

This causes boxing for any value type (like ValueTask<TResponse>).

The goal is to:

  1. Change the dictionary value types for TaskSendSwitchCase and ValueSendSwitchCase to object.
  2. Update the GenerateTaskSendCase and GenerateValueSendCase methods to remove the (object) cast within the generated delegates.
  3. In the Send<TResponse> and IValueSender.Send<TResponse> implementations, use Unsafe.As to cast the object delegate to the specialized Func signature and then call it.

Example for ValueTask:

if (ValueSendSwitchCase.Cases.TryGetValue(request.GetType(), out var handle))
{
    return global::System.Runtime.CompilerServices.Unsafe.As<object, global::System.Func<{{className}}, global::Mediator.Switch.IRequest<TResponse>, global::System.Threading.CancellationToken, global::System.Threading.Tasks.ValueTask<TResponse>>>(handle)(this, request, cancellationToken);
}

This ensures that the returned ValueTask<TResponse> is never cast to object, thus avoiding boxing entirely.

Files to modify:

  • src/Mediator.Switch.SourceGenerator/Generator/CodeGenerator.cs

Base branch for PR: copilot/implement-hybrid-valuetask-support

This pull request was created from Copilot chat.


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

…sk boxing

Co-authored-by: zachsaw <2786416+zachsaw@users.noreply.github.com>
Copilot AI changed the title [WIP] Refactor standard casts to Unsafe.As in Send methods Replace boxing casts with Unsafe.As in generated Send methods Feb 28, 2026
Comment thread README.md Outdated
…laim

Co-authored-by: zachsaw <2786416+zachsaw@users.noreply.github.com>
Copilot AI changed the title Replace boxing casts with Unsafe.As in generated Send methods Fix README allocation claims: V3.1 rename + IValueSender alloc-free correction Feb 28, 2026
@zachsaw zachsaw force-pushed the copilot/refactor-cast-to-unsafe-as branch from 0697d45 to 7284da6 Compare March 6, 2026 08:57
@zachsaw zachsaw merged commit 25b7f4e into main Mar 6, 2026
1 check passed
@zachsaw zachsaw deleted the copilot/refactor-cast-to-unsafe-as branch March 6, 2026 08:57
Copilot stopped work on behalf of zachsaw due to an error March 8, 2026 03:17
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.

2 participants