diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableExtensions.Minimal.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableExtensions.Minimal.cs index 66b365bad872b7..1434fa3b633afb 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableExtensions.Minimal.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableExtensions.Minimal.cs @@ -102,10 +102,10 @@ internal static bool TryCopyTo(this IEnumerable sequence, T[] array, int a Debug.Assert(array != null); Debug.Assert(arrayIndex >= 0 && arrayIndex <= array.Length); - // IList is the GCD of what the following types implement. - if (sequence is IList) + // Optimized paths for well-known types, all other ICollection implementations use the generic CopyTo fallback. + if (sequence is ICollection collection) { - if (sequence is List list) + if (collection is List list) { list.CopyTo(array, arrayIndex); return true; @@ -114,18 +114,31 @@ internal static bool TryCopyTo(this IEnumerable sequence, T[] array, int a // Array.Copy can throw an ArrayTypeMismatchException if the underlying type of // the destination array is not typeof(T[]), but is assignment-compatible with T[]. // See https://github.com/dotnet/runtime/issues/14794 for more info. - if (sequence.GetType() == typeof(T[])) + if (collection.GetType() == typeof(T[])) { - var sourceArray = (T[])sequence; + var sourceArray = (T[])collection; Array.Copy(sourceArray, 0, array, arrayIndex, sourceArray.Length); return true; } - if (sequence is ImmutableArray immutable) + if (collection is ImmutableArray immutable) { Array.Copy(immutable.array!, 0, array, arrayIndex, immutable.Length); return true; } + +#if !NET + // On .NET Framework, if 'sequence' is actually a covariant array (for example, a string[] assigned to object[] and passed as ICollection), + // sequence.GetType() won't match typeof(T[]), so the fast path above is skipped. + // The array's ICollection.CopyTo implementation may call Array.Copy and throw an ArrayTypeMismatchException when copying into a T[]. + if (collection is Array) + { + return false; + } +#endif + + collection.CopyTo(array, arrayIndex); + return true; } return false; diff --git a/src/libraries/System.Collections.Immutable/tests/ImmutableArrayTest.cs b/src/libraries/System.Collections.Immutable/tests/ImmutableArrayTest.cs index 6787c977ed55d4..ac06d1a7664891 100644 --- a/src/libraries/System.Collections.Immutable/tests/ImmutableArrayTest.cs +++ b/src/libraries/System.Collections.Immutable/tests/ImmutableArrayTest.cs @@ -1456,6 +1456,8 @@ public static IEnumerable InsertRangeData() yield return new object[] { s_empty, 0, new uint[] { 1, 2, 3 } }; yield return new object[] { s_manyElements, 0, new uint[] { 4, 5, 6 } }; yield return new object[] { s_manyElements, 3, new uint[] { 4, 5, 6 } }; + yield return new object[] { s_manyElements, 0, new Dictionary { [4] = 0, [5] = 0 }.Keys }; + yield return new object[] { s_manyElements, 3, new Dictionary { [4] = 0, [5] = 0 }.Keys }; } [Theory]