0

The following code creates an iterable of all the letters in the alphabet;

var alphabet = Enumerable.Range('a', 26).Select(c => (char)c);

Which works fine. However, the following doesn't work;

var alphabet = Enumerable.Range('a', 26).Cast<char>();

It throws an exception

"System.InvalidCastException: 'Unable to cast object of type 'System.Int32' to type 'System.Char'.'"

You may think this is a duplicate of this or this, but these relate to unboxing objects to a type that is not the original type. In this case, I have an IEnumerable<int>. Why can't I cast this element by element to IEnumerable<char>? They are both primitive types, not objects.

Steztric
  • 2,832
  • 2
  • 24
  • 43
  • 2
    Linq performs a generic cast, meaning it has to be of that type or subtype. It doesn't look at any implicit or explicit operators – pinkfloydx33 Apr 05 '20 at 13:02
  • @pinkfloydx33 exactly. The exception is so clear, datatypes are conflicting. – Mosia Thabo Apr 05 '20 at 13:03
  • @MosiaThabo What exactly do you mean "datatypes are conflicting"? A char is effectively an unsigned int under the hood. The problem is not a conflicting type, it is a failed cast. – Steztric Apr 05 '20 at 14:09
  • Not really. A char is a char... int is an int. They both are datatypes and are not interchangeable unless casted. – Mosia Thabo Apr 05 '20 at 14:10
  • The Error says "Unable to cast object of type 'System.Int32' to type 'System.Char" meaning int is not char and char is not int. But in practise you must cast these to either of them in order to achieve what you wish to achieve. that is like saying string "1" is an int. it may contain a number but it's not an integer unless casted to int. – Mosia Thabo Apr 05 '20 at 14:12

1 Answers1

2

The documentation for Enumerable.Cast<TResult> states the following:

The only type conversions that are performed by this method are reference conversions and unboxing conversions. The runtime type of the elements in the collection must match the target type, or in the case of value types, the runtime type of elements must be the result of a boxing conversion of the target type. Other conversion types, such as those between different numeric types, are not allowed.

So it seems, even though it is named Cast, it does not actually support casting values to different types.

Vera
  • 644
  • 5
  • 10
  • It's meant for "converting" untyped collections to typed ones. This is particularly useful for pre-generic collections. Think of like `DataRowCollection` which only implements `IEnumerable` even though each object is a `DataRow`. – pinkfloydx33 Apr 05 '20 at 13:07
  • I see. I'm guessing this limitation is something low down in the framework. I wonder if that is because an array of primitives has a size of n x element size, since the values are inline in the array. However, an array of reference types has a size of n x [size of pointer] since it is an array of pointers to the heap. When you are iterating over an array of reference types, you are always iterating in steps of [size of pointer] whereas the step size when iterating over an array of primitives depends on the size of the elements... – Steztric Apr 05 '20 at 14:15
  • It doesn't have anything to do with arrays or even iteration. – pinkfloydx33 Apr 05 '20 at 15:37