Consider the following enum declaration and int array:
enum Test { None };
int[] data = {0};
To convert this int[]
array to an Test[]
array we can simply do this:
Test[] result = Array.ConvertAll(data, element => (Test)element);
I initially tried to do this:
Test[] result = data.Cast<Test>().ToArray();
However, that throws an exception at runtime:
System.ArrayTypeMismatchException: Source array type cannot be assigned to destination array type.
Question One
Is there a way to do this using Linq and Cast<>
without an error, or must I just use Array.Convert()
?
Question Two (added after the first question was answered correctly)
Exactly why doesn't it work?
It seems like it's a case of an implementation detail escaping... Consider:
This causes an error:
var result = data.Cast<Test>().ToList(); // Happens with "ToList()" too.
But this does not:
var result = new List<Test>();
foreach (var item in data.Cast<Test>())
result.Add(item);
And neither does this:
var result = data.Select(x => x).Cast<Test>().ToList();
The clear implication is that some kind of optimisation is being done in the .ToList()
implementation that causes this exception.
Addendum:
This also works:
List<int> data = new List<int>{0};
var result = data.Cast<Test>().ToList();
or
List<int> data = new List<int>{0};
var result = data.Cast<Test>().ToArray();
It's only if the original data is an array that it doesn't work.
You can use .Select(e => (Test)e)
.
It doesn't work in this case because Cast
first performs the following check:
public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source)
{
IEnumerable<TResult> results = source as IEnumerable<TResult>;
if (results != null)
return results;
// ... the rest of the method
}
It turns out that for int[]
this check succeeds (so int[]
as IEnumerable<Test>
is not null). In result, Cast
actually does nothing at all, it returns array as is. Then when you call ToArray
, Array.Copy
is invoked. It tries to copy from int[]
array to Test[]
array, and fails because of type mismatch. This exception you see.
Because the cast actually did not do anything since it thinks that the collection is already the desire type
IEnumerable<Test> cast = data.Cast<Test>();
IEnumerable<Test> select = data.Select(e => (Test) e);
Console.WriteLine(cast == (IEnumerable<int>) data); //True
Console.WriteLine(select == (IEnumerable<int>) data); //False
Console.WriteLine(select == cast); //Flase
as you can see the cast IEnumerable
is actually just the original array. Thus .ToArray
is trying to do something similar to (Test[]) data.ToArray();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With