Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between directly casting an array or using System.Linq.Cast?

Suppose I have 2 classes, A and B, and B can be cast to A. I declared an array of type B[] called b. Then if I wanted to cast b to A[], what's the difference between (A[])b and b.Cast<A>()?

like image 274
palapapa Avatar asked Sep 19 '25 12:09

palapapa


1 Answers

These are two different things.

Language casting

(A[])b cast b to type A[] and does not compile or throws an exception at runtime if b is not type of A[].

Take for example the case of doubles and integers:

var array = new object[2];

array[0] = 10.2;
array[1] = 20.8;

var casted = (int[])array; // does not compile here,
                           // or throw an exception at runtime if types mismatch

Here we just cast a type to another, no matter what they are, collection or not.

Casting and type conversions (C# Programming Guide)

Linq Cast

Cast<TResult> convert each items of an IEnumerable to TResult.

It's just a LINQ loop already written to make our life easier over boxed values.

Enumerable.Cast(IEnumerable) Method

Casts the elements of an IEnumerable to the specified type.

From the source code

static IEnumerable<TResult> CastIterator<TResult>(IEnumerable source)
{
  foreach (object obj in source) yield return (TResult)obj;
}

Thus this method can be used to unbox boxed values from a collection like Rows of a DataGridView or any similar "reduced" collections like for example Items in a ListBox or a ComboBox.

That means that the type of the items must be type of TResult or ancestor.

Example

var array = new object[2];

array[0] = 10.2;
array[1] = 20.8;

var converted = array.Cast<int>(); // compiles but will not work
                                   // and throw an InvalidCastException 

Note

Because of the yielding, Cast method is deferred, so we get the result only when it is executed, for example using foreach or ToList.

Deferred Execution of LINQ Query

Deferred Vs Immediate Query Execution in LINQ

Deferred execution and lazy evaluation

Alternative to solve the problem on the sample

Therefore to convert the array, we can use a direct cast using for example a foreach or Select:

var converted = array.Select(v => (int)v).ToArray(); // get int[]

Console.WriteLine(string.Join(Environment.NewLine, converted));

> 10
> 20

Using an extension method

static public class EnumerableHelper
{
  static public IEnumerable<TResult> Cast<TSource, TResult>(this IEnumerable<TSource> source)
    where TSource : IConvertible
  {
    foreach ( TSource obj in source )
      yield return (TResult)Convert.ChangeType(obj, typeof(TResult));
  }
}

var converted = array.Cast<double, int>();

> 10
> 21

Also CultureInfo.InvariantCulture to avoid problems on numbers, as well as a formatter to avoid roundings.