Skip to content

Use ICollection<T> check instead of IList<T> in TryCopyTo#125304

Open
prozolic wants to merge 6 commits intodotnet:mainfrom
prozolic:TryCopyTo
Open

Use ICollection<T> check instead of IList<T> in TryCopyTo#125304
prozolic wants to merge 6 commits intodotnet:mainfrom
prozolic:TryCopyTo

Conversation

@prozolic
Copy link
Copy Markdown
Contributor

@prozolic prozolic commented Mar 8, 2026

#88181

This PR change the type check from IList to ICollection. With this change, collections that implement ICollection will have ICollection.CopyTo invoked.

  • Change the type check from IList<T> to ICollection<T>
  • If the type does not match List<T>, T[], or ImmutableArray<T>, fall back to ICollection<T>.CopyTo
  • Add conditional compilation( #if NET) to ensure the sequence is not an array before falling back to ICollection<T>.CopyTo to avoid issues with array covariance in .NET Framework

Benchmark

#88181 (comment)

This PR change the type check from IList<T> to ICollection<T>.
With this change, collections that implement ICollection<T> will
have ICollection<T>.CopyTo invoked.
Copilot AI review requested due to automatic review settings March 8, 2026 12:51
@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates that the PR has been added by a community member label Mar 8, 2026
@dotnet-policy-service
Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-system-collections
See info in area-owners.md if you want to be subscribed.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR changes ImmutableExtensions.TryCopyTo to use ICollection<T> as the type gate instead of IList<T>. This allows collections that implement ICollection<T> but not IList<T> (such as Dictionary<K,V>.Keys and Dictionary<K,V>.Values) to benefit from the fast CopyTo path rather than falling back to per-element enumeration. The performance motivation is that LINQ's own ToArray already takes this ICollection<T> path, and the previous restriction was making immutable collection operations unnecessarily slower.

Changes:

  • Changes the outer type check from IList<T> to ICollection<T>, broadening the fast-copy path to any ICollection<T> implementation.
  • After the well-known-type fast paths (List<T>, exact T[], ImmutableArray<T>), falls through to a generic ICollection<T>.CopyTo call for all other implementors.
  • Adds a #if !NET guard to skip arrays that are not exactly T[] (covariant arrays) when running on .NET Framework, where ICollection<T>.CopyTo on such arrays can throw ArrayTypeMismatchException.

You can also share your feedback on Copilot code review. Take the survey.

prozolic and others added 2 commits March 8, 2026 22:14
…ons/Immutable/ImmutableExtensions.Minimal.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 8, 2026 13:15
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.


You can also share your feedback on Copilot code review. Take the survey.

@stephentoub
Copy link
Copy Markdown
Member

@prozolic
Copy link
Copy Markdown
Contributor Author

prozolic commented Mar 9, 2026

Thanks for the pointer. You're right that the original IList restriction was intentional.
The implementation approach follows what was discussed and considered in #88181 (#88093 (comment)).
@adamsitnik also confirmed in #88181 that the benchmark results look good.

@danmoseley danmoseley requested a review from adamsitnik March 16, 2026 02:06
Copilot AI review requested due to automatic review settings April 10, 2026 23:05
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

if (sequence is ICollection<T> collection)
{
if (sequence is List<T> list)
if (collection is List<T> list)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Are all these secondary type checks (where it has to enumerate through the types/interfaces to see if it is that type) better than just doing collection.CopyTo(...)?

I'd expect the virtual dispatch overhead, especially with DPGO/guarded-devirtualization to be cheaper and that we could get this down to basically just the type check for ICollection and one more for the array special handling for the common path. Rather than needing up to 4-5.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-System.Collections community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants