Use ICollection<T> check instead of IList<T> in TryCopyTo#125304
Use ICollection<T> check instead of IList<T> in TryCopyTo#125304prozolic wants to merge 4 commits intodotnet:mainfrom
Conversation
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.
|
Tagging subscribers to this area: @dotnet/area-system-collections |
There was a problem hiding this comment.
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>toICollection<T>, broadening the fast-copy path to anyICollection<T>implementation. - After the well-known-type fast paths (
List<T>, exactT[],ImmutableArray<T>), falls through to a genericICollection<T>.CopyTocall for all other implementors. - Adds a
#if !NETguard to skip arrays that are not exactlyT[](covariant arrays) when running on .NET Framework, whereICollection<T>.CopyToon such arrays can throwArrayTypeMismatchException.
You can also share your feedback on Copilot code review. Take the survey.
...System.Collections.Immutable/src/System/Collections/Immutable/ImmutableExtensions.Minimal.cs
Show resolved
Hide resolved
...System.Collections.Immutable/src/System/Collections/Immutable/ImmutableExtensions.Minimal.cs
Outdated
Show resolved
Hide resolved
...System.Collections.Immutable/src/System/Collections/Immutable/ImmutableExtensions.Minimal.cs
Outdated
Show resolved
Hide resolved
…ons/Immutable/ImmutableExtensions.Minimal.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
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.
| #if !NET | ||
| // On .NET Framework, if 'sequence' is actually a covariant array (for example, string[] used as ICollection<object>), | ||
| // its ICollection<T>.CopyTo implementation may call Array.Copy and throw an ArrayTypeMismatchException when copying into a T[]. | ||
| if (sequence is Array) | ||
| { | ||
| return false; | ||
| } |
There was a problem hiding this comment.
The comment in the #if !NET guard states: "if 'sequence' is actually a covariant array (for example, string[] used as ICollection<object>)". This example is incorrect: generic interfaces like ICollection<T> are invariant, so string[] cannot satisfy ICollection<object>. Therefore, a string[] would not pass the sequence is ICollection<T> guard at all when T is object, making it impossible to reach this code with that example. A more accurate explanation might reference situations where an array subtype passes the ICollection<T> check on .NET Framework despite the sequence.GetType() == typeof(T[]) check not matching. If no such scenario exists, the guard and comment should explain the actual risk more precisely, or be documented as a conservative safety measure.
|
https://github.com/dotnet/runtime/pull/125304/changes#diff-79ebb1b84d82a6117697d669c596bdcb999803d9ecf5a5339d6431d1ac0c5f7eR93-R96 suggests the lack of this is on purpose |
|
Thanks for the pointer. You're right that the original IList restriction was intentional. |
#88181
This PR change the type check from IList to ICollection. With this change, collections that implement ICollection will have ICollection.CopyTo invoked.
IList<T>toICollection<T>List<T>,T[], orImmutableArray<T>, fall back toICollection<T>.CopyTo#if NET) to ensure the sequence is not an array before falling back toICollection<T>.CopyToto avoid issues with array covariance in .NET FrameworkBenchmark
#88181 (comment)