82

I see this Array.ConvertAll method, but it requires a Converter as an argument. I don't see why I need a converter, when I've already defined an implicit one in my class:

    public static implicit operator Vec2(PointF p)
    {
        return new Vec2(p.X, p.Y);
    }

I'm trying to cast an array of PointFs to an array of Vec2s. Is there a nice way to do this? Or should I just suck it up and write (another) converter or loop over the elements?

mpen
  • 272,448
  • 266
  • 850
  • 1,236
  • 5
    @Terry: I ask a lot of trivial questions because I'm always surprised by the answers :) It's easy to solve a problem, but hard to do it elegantly. – mpen Jan 15 '10 at 00:24
  • Duplicate: http://stackoverflow.com/questions/944174/best-way-to-cast-from-animal-to-dog – Mikhail Poda Jan 15 '10 at 16:18

5 Answers5

126

The proposed LINQ solution using Cast/'Select' is fine, but since you know you are working with an array here, using ConvertAll is rather more efficienct, and just as simple.

var newArray = Array.ConvertAll(array, item => (NewType)item);

Using ConvertAll means
a) the array is only iterated over once,
b) the operation is more optimised for arrays (does not use IEnumerator<T>).

Don't let the Converter<TInput, TOutput> type confuse you - it is just a simple delegate, and thus you can pass a lambda expression for it, as shown above.

Scott Solmer
  • 3,871
  • 6
  • 44
  • 72
Noldorin
  • 144,213
  • 56
  • 264
  • 302
  • Works perfectly! Thank you! I thought I had to define the ``. – mpen Jan 15 '10 at 00:22
  • 3
    No problem. And yeah, in C# 2.0 and before you would have had to define a type - fortunately those days are gone. – Noldorin Jan 15 '10 at 00:39
  • 3
    um, actually, I believe none of the proposed solutions will make the array be iterated twice, since both Cast and Select are implemented using deferred execution: https://msdn.microsoft.com/en-us/library/bb341406(v=vs.90).aspx#Anchor_2 https://msdn.microsoft.com/en-us/library/bb548891(v=vs.90).aspx#Anchor_2 – geekley Jul 19 '18 at 20:14
43

As an update to this old question, you can now do:

myArray.Cast<Vec2>().ToArray();

where myArray contains the source objects, and Vec2 is the type you want to cast to.

Ravi
  • 439
  • 4
  • 3
22

Cast doesn't consider user defined implicit conversions so you can't cast the array like that. You can use select instead:

myArray.Select(p => (Vec2)p).ToArray();

Or write a converter:

Array.ConvertAll(points, (p => (Vec2)p));

The latter is probably more efficient as the size of the result is known in advance.

Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
5

The most efficient way is:

class A { };
class B : A { };

A[] a = new A[9];
B[] b = a as B[];
fdafadf
  • 809
  • 5
  • 13
  • 1
    This is fast but `b` will always be `null`. You can't cast from an `A[]` to a `B[]` because the `A` array may contain non-`B` instances (e.g. `C : A`); that is, not every `A` is necessarily also a `B`. Instead, if you did `B[] b = new B[9]; A[] a = b as A[];` then that would succeed because you are casting from a _more-derived_ array type to a _less-derived_ array type. You could even use `A[] a = (A[]) b;` because `as` would never fail to upcast. Even better would be `A[] a = b;` because the _compiler_ knows that every `B` is also an `A`, therefore every `B[]` is also an `A[]`. – Lance U. Matthews Nov 02 '21 at 04:44
2

This is an answer related to a bounty question asked by @user366312 and not to the original question.

What would be the solution in the case of .NET Framework 2.0?

As far as I know, LINQ was introduced to the.NET framework with version 3.5 back in 2007. So this means it is not possible to use LINQ in .NET Framework 2.0.

Therefore I would use just a regular for-loop and cast each element in the array.

Something like this without testing it:

var newArray = new NewType[myArray.Length];

for (var i = 0; i < myArray.Length; i++)
{
    newArray[i] = (NewType)myArray[i];
}

You can wrap it up in a method like:

public static NewType[] ConvertAll(Vec2[] myArray)
{
    var newArray = new NewType[myArray.Length];

    for (var i = 0; i < myArray.Length; i++)
    {
        newArray[i] = (NewType)myArray[i];
    }

    return newArray;
}

And use it

var newArray = ConvertAll(myArray);
Maytham Fahmi
  • 31,138
  • 14
  • 118
  • 137