Reputation: 12403
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
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
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
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
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