Skip to content

Commit 0c11cd9

Browse files
committed
Fix TypeCastingList.CopyTo() type conversion issue.
1 parent b7f95f4 commit 0c11cd9

File tree

2 files changed

+90
-2
lines changed

2 files changed

+90
-2
lines changed

Core.Tests/Collections/ListExtensionsTests.cs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using NUnit.Framework;
22
using System;
3+
using System.Collections;
34
using System.Collections.Generic;
45
using System.Linq;
56

@@ -123,6 +124,73 @@ public void BinarySearchTest()
123124
}
124125

125126

127+
/// <summary>
128+
/// Test for <see cref="ListExtensions.Cast{TOut}(System.Collections.IList)"/>.
129+
/// </summary>
130+
[Test]
131+
public void CastingTest()
132+
{
133+
// prepare
134+
var sourceList = (IList)new int[1024].Also((it) =>
135+
{
136+
for (var i = it.Length - 1; i >= 0; --i)
137+
it[i] = this.random.Next(int.MinValue, int.MaxValue);
138+
});
139+
140+
// cast to IList<int>
141+
var intList = sourceList.Cast<int>();
142+
Assert.AreEqual(sourceList.Count, intList.Count);
143+
for (var i = intList.Count - 1; i >= 0; --i)
144+
Assert.AreEqual(sourceList[i], intList[i]);
145+
146+
// copy from IList<int> to array
147+
var intArray = new int[intList.Count];
148+
intList.CopyTo(intArray, 0);
149+
for (var i = intArray.Length - 1; i >= 0; --i)
150+
Assert.AreEqual(sourceList[i], intArray[i]);
151+
152+
// cast to IList<object>
153+
var objList = sourceList.Cast<object>();
154+
Assert.AreEqual(sourceList.Count, objList.Count);
155+
for (var i = objList.Count - 1; i >= 0; --i)
156+
Assert.AreEqual(sourceList[i], objList[i]);
157+
158+
// copy from IList<object> to array
159+
var objArray = new object[objList.Count];
160+
objList.CopyTo(objArray, 0);
161+
for (var i = objArray.Length - 1; i >= 0; --i)
162+
Assert.AreEqual(sourceList[i], objArray[i]);
163+
164+
// cast to IList<IConvertible>
165+
var convertibleList = sourceList.Cast<IConvertible>();
166+
Assert.AreEqual(sourceList.Count, convertibleList.Count);
167+
for (var i = convertibleList.Count - 1; i >= 0; --i)
168+
Assert.AreEqual(sourceList[i], convertibleList[i]);
169+
170+
// copy from IList<IConvertible> to array
171+
var convertibleArray = new IConvertible[convertibleList.Count];
172+
convertibleList.CopyTo(convertibleArray, 0);
173+
for (var i = convertibleArray.Length - 1; i >= 0; --i)
174+
Assert.AreEqual(sourceList[i], convertibleArray[i]);
175+
176+
// cast to IList<string>
177+
try
178+
{
179+
sourceList.Cast<string>();
180+
throw new AssertionException("Should not support type casting.");
181+
}
182+
catch (Exception ex)
183+
{
184+
if (ex is AssertionException)
185+
throw;
186+
}
187+
188+
// cast empty list.
189+
var emptyList = ((IList)new int[0]).Cast<string>();
190+
Assert.AreEqual(0, emptyList.Count);
191+
}
192+
193+
126194
/// <summary>
127195
/// Test for copying elements of list to array.
128196
/// </summary>

Core/Collections/TypeCastingList.cs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,28 @@ public bool Contains(T element) =>
3333

3434

3535
/// <inheritdoc/>
36-
public void CopyTo(T[] array, int arrayIndex) =>
37-
this.list.CopyTo(array, arrayIndex);
36+
public void CopyTo(T[] array, int arrayIndex)
37+
{
38+
var list = this.list;
39+
var count = list.Count;
40+
if (count == 0)
41+
return;
42+
var elementType = (Type?)null;
43+
for (var i = count - 1; i >= 0; --i)
44+
{
45+
elementType = list[i]?.GetType();
46+
if (elementType != null)
47+
break;
48+
}
49+
if (elementType == typeof(T))
50+
list.CopyTo(array, arrayIndex);
51+
else if (elementType != null)
52+
{
53+
var tempArray = Array.CreateInstance(elementType, count);
54+
list.CopyTo(tempArray, 0);
55+
Array.Copy(tempArray, 0, array, arrayIndex, count);
56+
}
57+
}
3858

3959

4060
/// <inheritdoc/>

0 commit comments

Comments
 (0)