Martin
Martin

Reputation: 12403

Is this C# casting useless?

I have two methods like so:

Foo[] GetFoos(Type t) { //do some stuff and return an array of things of type T }

T[] GetFoos<T>()
    where T : Foo
{
    return GetFoos(typeof(T)) as T[];
}

However, this always seems to return null. Am I doing things wrong or is this just a shortfall of C#?

Nb: I know I could solve this problem with:

GetFoos(typeof(T)).Cast<T>().ToArray();

However, I would prefer to do this wothout any allocations (working in an environment very sensitive to garbage collections).

Nb++: Bonus points if you suggest an alternative non allocating solution

Edit: This raises an interesting question. The MSDN docs here: http://msdn.microsoft.com/en-us/library/aa664572%28v=vs.71%29.aspx say that the cast will succeed if there is an implicit or explicit cast. In this case there is an explicit cast, and so the cast should succeed. Are the MSDN docs wrong?

Upvotes: 0

Views: 114

Answers (4)

Jeff Mercado
Jeff Mercado

Reputation: 134841

From what I understand from your situation, using System.Array in place of a more specific array can help you. Remember, Array is the base class for all strongly typed arrays so an Array reference can essentially store any array. You should make your (generic?) dictionary map Type -> Array so you may store any strongly typed array also while not having to worry about needing to convert one array to another, now it's just type casting.

i.e.,

Dictionary<Type, Array> myDict = ...;
Array GetFoos(Type t)
{
    // do checks, blah blah blah
    return myDict[t];
}
// and a generic helper
T[] GetFoos<T>() where T: Foo
{
    return (T[])GetFoos(typeof(T));
}

// then accesses all need casts to the specific type
Foo[] f = (Foo[])GetFoos(typeof(Foo));
DerivedFoo[] df = (DerivedFoo[])GetFoos(typeof(DerivedFoo));
// or with the generic helper
AnotherDerivedFoo[] adf = GetFoos<AnotherDerivedFoo>();
// etc...

p.s., The MSDN link that you provide shows how arrays are covariant. That is, you may store an array of a more derived type in a reference to an array of a base type. What you're trying to achieve here is contravariance (i.e., using an array of a base type in place of an array of a more derived type) which is the other way around and what arrays can't do without doing a conversion.

Upvotes: 0

Femaref
Femaref

Reputation: 61437

No, C# casting isn't useless - you simply can't cast a Foo[] to a T[] where T is a more derived type, as the Foo[] could contain other elements different to T. Why don't you adjust your GetFoos method to GetFoos<T>()? A method only taking a Type object can easily be converted into a generic method, where you could create the array directly via new T[].

If this is not possible: Do you need the abilities an array offers (ie. indexing and things like Count)? If not, you can work with an IEnumerable<T> without having much of a problem. If not: you won't get around going the Cast<T>.ToArray() way.

Edit:

There is no possible cast from Foo[] to T[], the description in your link is the other way round - you could cast a T[] to a Foo[] as all T are Foo, but not all Foo are T.

Upvotes: 2

James Black
James Black

Reputation: 41858

I haven't tried this, but it should work:

T[] array = Array.ConvertAll<Foo, T>(input,
    delegate(Foo obj)
    {
        return (T)obj;
    });

You can find more at http://msdn.microsoft.com/en-us/library/exc45z53(v=VS.85).aspx

I think this converts in-place, so it won't be doing any re-allocations.

Upvotes: 0

C. K. Young
C. K. Young

Reputation: 223003

If you can arrange for GetFoos to create the return array using new T[], then you win. If you used new Foo[], then the array's type is fixed at that, regardless of the types of the objects it actually holds.

Upvotes: 1

Related Questions