Consider this contrived, trivial example:
var foo = new byte[] {246, 127};
var bar = foo.Cast();
var baz = new List();
Okay, this really depends on a few oddities combined:
Even though in C# you can't cast a byte[]
to an sbyte[]
directly, the CLR allows it:
var foo = new byte[] {246, 127};
// This produces a warning at compile-time, and the C# compiler "optimizes"
// to the constant "false"
Console.WriteLine(foo is sbyte[]);
object x = foo;
// Using object fools the C# compiler into really consulting the CLR... which
// allows the conversion, so this prints True
Console.WriteLine(x is sbyte[]);
Cast<T>()
optimizes such that if it thinks it doesn't need to do anything (via an is
check like the above) it returns the original reference - so that's happening here.
ToList()
delegates to the constructor of List<T>
taking an IEnumerable<T>
That constructor is optimized for ICollection<T>
to use CopyTo
... and that's what's failing. Here's a version which has no method calls other than CopyTo
:
object bytes = new byte[] { 246, 127 };
// This succeeds...
ICollection<sbyte> list = (ICollection<sbyte>) bytes;
sbyte[] array = new sbyte[2];
list.CopyTo(array, 0);
Now if you use a Select
at any point, you don't end up with an ICollection<T>
, so it goes through the legitimate (for the CLR) byte
/sbyte
conversion for each element, rather than trying to use the array implementation of CopyTo
.