Skip to content

Add DeepCloneFrom for Stack, Queue, ConcurrentStack and ConcurrentQueue [minor] - #115

Merged
matt-edmondson merged 2 commits into
mainfrom
fix/deepclonefrom-stack-queue
Nov 4, 2026
Merged

matt-edmondson merged 2 commits into
mainfrom
fix/deepclonefrom-stack-queue

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

The README teaches clone.Items.DeepCloneFrom(Items) for get-only collection properties. That pattern needs ICollection<T> or IDictionary<TKey, TValue>. Stack<T>, Queue<T>, ConcurrentStack<T> and ConcurrentQueue<T> implement neither, so it failed with CS1929. The workaround most people reach for, pushing each item of Undo.DeepClone(), compiles but reverses the stack.

This adds four in-place DeepCloneFrom overloads. Each one:

Per-type details:

  • Stack<T>: pushes the snapshot in reverse.
  • ConcurrentStack<T>: builds the reversed clones first, then calls Clear and PushRange.
  • ConcurrentQueue<T>: calls Clear on netstandard2.1 and .NET. netstandard2.0 has no Clear, so it drains with TryDequeue instead.

The remarks note that on the concurrent types, clear-and-refill isn't atomic.

ConcurrentBag<T> is left out on purpose. It has no defined order, and the issue lists it as optional.

The README's DeepCloneFrom table now lists the new receivers.

Tests

New InPlaceStackQueueTests:

  • For each type, the clone pops or dequeues in the source order, every item is a distinct instance, and existing contents of dest are replaced.
  • Self-clone leaves each of the four collections unchanged.
  • A DeepCloneable with get-only Stack<T> and ConcurrentQueue<T> properties uses the README pattern, and its clone has the right order.

Validation:

  • With the library change stashed, the test project fails to compile with CS1929 on all four receiver types.
  • With the change, all 72 tests pass on net10.0.
  • The library builds for netstandard2.0, netstandard2.1, net8.0, net9.0 and net10.0.

Fixes #114


Generated by Claude Code

…currentQueue

Stack<T>, Queue<T>, ConcurrentStack<T> and ConcurrentQueue<T> don't implement
ICollection<T>, so the documented clone.Items.DeepCloneFrom(Items) pattern didn't
compile for get-only properties of those types, and the usual manual copy
reversed stacks. Each new overload snapshots the source first (so self-clone is
safe), clears the destination and refills it in source order.

Fixes #114

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017vfJW4ekcBueRdQ8TsyWTk
@sonarqubecloud

sonarqubecloud Bot commented Nov 1, 2026

Copy link
Copy Markdown

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.

DeepCloneFrom doesn't compile for get-only Stack/Queue/ConcurrentQueue/ConcurrentStack properties, and the obvious manual copy reverses a stack

2 participants