diff --git a/.ncrunch/Avalonia.Controls.UnitTests.net47.v3.ncrunchproject b/.ncrunch/Avalonia.Controls.UnitTests.net47.v3.ncrunchproject
index e9d39b0c74..f30a20df78 100644
--- a/.ncrunch/Avalonia.Controls.UnitTests.net47.v3.ncrunchproject
+++ b/.ncrunch/Avalonia.Controls.UnitTests.net47.v3.ncrunchproject
@@ -3,5 +3,6 @@
MissingOrIgnoredProjectReference
+ Avalonia.Controls.UnitTests.TimePickerTests
\ No newline at end of file
diff --git a/src/Avalonia.Base/Collections/AvaloniaList.cs b/src/Avalonia.Base/Collections/AvaloniaList.cs
index f201cfab1f..d43b4e04bb 100644
--- a/src/Avalonia.Base/Collections/AvaloniaList.cs
+++ b/src/Avalonia.Base/Collections/AvaloniaList.cs
@@ -543,7 +543,73 @@ namespace Avalonia.Collections
///
void ICollection.CopyTo(Array array, int index)
{
- _inner.CopyTo((T[])array, index);
+ if (array == null)
+ {
+ throw new ArgumentNullException(nameof(array));
+ }
+
+ if (array.Rank != 1)
+ {
+ throw new ArgumentException("Multi-dimensional arrays are not supported.");
+ }
+
+ if (array.GetLowerBound(0) != 0)
+ {
+ throw new ArgumentException("Non-zero lower bounds are not supported.");
+ }
+
+ if (index < 0)
+ {
+ throw new ArgumentException("Invalid index.");
+ }
+
+ if (array.Length - index < Count)
+ {
+ throw new ArgumentException("The target array is too small.");
+ }
+
+ if (array is T[] tArray)
+ {
+ _inner.CopyTo(tArray, index);
+ }
+ else
+ {
+ //
+ // Catch the obvious case assignment will fail.
+ // We can't find all possible problems by doing the check though.
+ // For example, if the element type of the Array is derived from T,
+ // we can't figure out if we can successfully copy the element beforehand.
+ //
+ Type targetType = array.GetType().GetElementType()!;
+ Type sourceType = typeof(T);
+ if (!(targetType.IsAssignableFrom(sourceType) || sourceType.IsAssignableFrom(targetType)))
+ {
+ throw new ArgumentException("Invalid array type");
+ }
+
+ //
+ // We can't cast array of value type to object[], so we don't support
+ // widening of primitive types here.
+ //
+ object[] objects = array as object[];
+ if (objects == null)
+ {
+ throw new ArgumentException("Invalid array type");
+ }
+
+ int count = _inner.Count;
+ try
+ {
+ for (int i = 0; i < count; i++)
+ {
+ objects[index++] = _inner[i];
+ }
+ }
+ catch (ArrayTypeMismatchException)
+ {
+ throw new ArgumentException("Invalid array type");
+ }
+ }
}
///
diff --git a/tests/Avalonia.Base.UnitTests/Collections/AvaloniaListTests.cs b/tests/Avalonia.Base.UnitTests/Collections/AvaloniaListTests.cs
index 19700cadab..d5ac01a092 100644
--- a/tests/Avalonia.Base.UnitTests/Collections/AvaloniaListTests.cs
+++ b/tests/Avalonia.Base.UnitTests/Collections/AvaloniaListTests.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
@@ -334,5 +335,27 @@ namespace Avalonia.Base.UnitTests.Collections
Assert.True(raised);
}
+
+ [Fact]
+ public void Can_CopyTo_Array_Of_Same_Type()
+ {
+ var target = new AvaloniaList { "foo", "bar", "baz" };
+ var result = new string[3];
+
+ target.CopyTo(result, 0);
+
+ Assert.Equal(target, result);
+ }
+
+ [Fact]
+ public void Can_CopyTo_Array_Of_Base_Type()
+ {
+ var target = new AvaloniaList { "foo", "bar", "baz" };
+ var result = new object[3];
+
+ ((IList)target).CopyTo(result, 0);
+
+ Assert.Equal(target, result);
+ }
}
}