views:

69

answers:

3

Hi,

I have the following classes with an implicit cast operator defined:

class A
{
    ...
}
class B
{
    private A m_a;

    public B(A a)
    {
        this.m_a = a;
    }

    public static implicit operator B(A a)
    {
        return new B(a);
    }
}

Now, I can implicitly cast A to B.

But why can't I implicitly cast A[] to B[] ?

static void Main(string[] args)
{
    // compiles
    A a = new A();
    B b = a;

    // doesn't compile
    A[] arrA = new A[] {new A(), new A()};
    B[] arrB = arrA;
}

Thanks, Malki.

+4  A: 

Array covariance only works for reference types and in the inheritance hierarchy (note that it's not a representation-changing conversion: just a set of pointers with identical size interpreted differently.) It will not work for value types and user defined conversions.

Mehrdad Afshari
Also, covariance of that sort will only work in .NET 4.
Randolpho
@Randolpho: Not true. Array covariance has been around since .NET 1.0. It's not statically checked safe co/contra-variance for *generics* that's new in .NET 4.
Mehrdad Afshari
Heh... Good point.
Randolpho
Can't I write an implicit cast method that casts from A[] to B[] ?I don't mind having to loop through the array and casting each object individually into the other array.Can't it be done? (I can't seem to find the syntax for that...)
Malki
@Malki: if you don't mind a loop and cast/copy, just use my suggested answer; the methods I mention will do the loop and copy for you.
Randolpho
@Randolpho: Thanks, that does help, but I really was looking for a way to do that implicitly... :\
Malki
@Malki: keep in mind that your implicit operator doesn't actually cast; it's instantiating a new object. Granted, that object references the original item, but it's still, essentially, a shallow copy. You may be better off reconsidering your approach and going with the explicit cast.
Randolpho
+1  A: 

As Mehrdad Afshari mentioned, you're out of luck doing this implicitly. You'll have to get explicit, and it'll involve an array copy. Thankfully, you can probably do it with a one-liner:

arrB = arrA.Cast<B>().ToArray();

Although if you only want to iterate arrB in a foreach statement, you can avoid the copy by omitting ToArray()

Randolpho
Array.ConvertAll has this covered already http://msdn.microsoft.com/en-us/library/exc45z53.aspx
bottlenecked
@bottlenecked: excellent point. `ConvertAll` *will* do the same thing as my example. It won't, however, allow for iteration against the array as a different type without copying the array, which a simple call to `Cast` will allow. If a copy is needed, `ConvertAll`. If iteration is needed, `Cast`.
Randolpho
A: 

Imagine for a moment if Arrays used the same syntax as other collections in .Net, and what you're trying to compare is an Array<A> with an Array<B>. You wouldn't compare a List<A> to a List<B>. Well, that's essentially what you're trying.

I'd recommend using a simple extension method to get the result you want, you'll need to change your syntax slightly to say 'B[] arrB = arrA.ToBArray();`

static class ArrayCast {
    public static B[] ToBArray(this A[] source) {
        var result = new B[source.Length];
        for (int i = 0;i < source.Length;i++)
            result[i] = source[i];
        return result;
    }
}
Mark H