Okay, this really depends on a few oddities combined:
-
Even though in C# you can’t cast a
byte[]to ansbyte[]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 anischeck like the above) it returns the original reference – so that’s happening here. -
ToList()delegates to the constructor ofList<T>taking anIEnumerable<T> -
That constructor is optimized for
ICollection<T>to useCopyTo… and that’s what’s failing. Here’s a version which has no method calls other thanCopyTo: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.