Reputation: 86154
This would be pretty straight forward if I knew the types at compile time or if it was a generic parameter, because I could do something like myArray.Cast<T>()
But what I actually have is essentially this. I do not have a known type or generic parameter. I have a System.Type
variable.
// could actually be anything else
Type myType = typeof(string);
// i already know all the elements are the correct types
object[] myArray = new object[] { "foo", "bar" };
Is there some kind of reflection magic I can do to get a string[]
reference containing the same data? (where string
isn't known at compile time)
Upvotes: 18
Views: 14553
Reputation: 3801
I would say the answer is it cant be cast. I know alot of other people have offered solutions, but the answer is no. I think the reason is because the type of the array is object, which is lower than string. The compiler will not let the upconversion happen unless you do it manually. I also played around with the DLR stuff, but it still types it as object.
class Program
{
static void Main(string[] args)
{
// could actually be anything else
Type myType = typeof(string);
Type myArrayType = Array.CreateInstance(myType, 1).GetType();
// i already know all the elements are the correct types
object[] myArray = new object[] { "foo", "bar" };
MethodInfo castMethod = typeof(Enumerable).GetMethod("Cast").MakeGenericMethod(myArrayType);
object castedObject = castMethod.Invoke(null, new object[] { myArray });
}
public static T Cast<T>(object o)
{
return (T)o;
}
}
Upvotes: 1
Reputation: 8911
This is not a one liner but it can be done with two lines. Given your specified Array
of elements of the correct type myArray
and the specified Type
parameter myType
, dynamically calling .Cast<"myType">.ToArray()
would work.
var typeConvertedEnumerable = typeof(System.Linq.Enumerable)
.GetMethod("Cast", BindingFlags.Static | BindingFlags.Public)
.MakeGenericMethod(new Type[] { myType })
.Invoke(null, new object[] { myArray });
var typeConvertedArray = typeof(System.Linq.Enumerable)
.GetMethod("ToArray", BindingFlags.Static | BindingFlags.Public)
.MakeGenericMethod(new Type[] { myType })
.Invoke(null, new object[] { typeConvertedEnumerable });
While the method generation is slower than a direct call, it is O(1) on the size of the array. The benefit of this approach is, if IEnumerable<"myType">
would be acceptable, the second line is not needed, and therefore I do not believe the array will be copied.
Upvotes: 3
Reputation: 11230
You can't perform such a cast, because the arrays object[] and string[] are actually different types and are not convertible. However, if you wanted to pass different such types to a function, just make the parameter IEnumerable. You can then pass an array of any type, list of any type, etc.
// Make an array from any IEnumerable (array, list, etc.)
Array MakeArray(IEnumerable parm, Type t)
{
if (parm == null)
return Array.CreateInstance(t, 0);
int arrCount;
if (parm is IList) // Most arrays etc. implement IList
arrCount = ((IList)parm).Count;
else
{
arrCount = 0;
foreach (object nextMember in parm)
{
if (nextMember.GetType() == t)
++arrCount;
}
}
Array retval = Array.CreateInstance(t, arrCount);
int ix = 0;
foreach (object nextMember in parm)
{
if (nextMember.GetType() == t)
retval.SetValue(nextMember, ix);
++ix;
}
return retval;
}
Upvotes: 2
Reputation: 59543
This will create the array that you want, but I don't know what you're going to do with it afterwards, since the compiler still doesn't know what the type of the array object is.
Type myType = typeof(string);
object[] myArray = new object[] { "foo", "bar" };
Array myArrayOfTheCorrectType = Array.CreateInstance(myType, myArray.Length);
for (int index = 0; index < myArray.Length; index++)
myArrayOfTheCorrectType.SetValue(myArray[index], index);
Upvotes: 1
Reputation: 22703
It's not really a cast as such (I'm allocating a new array and copying the original), but maybe this can help you out?
Type myType = typeof(string);
object[] myArray = new object[] { "foo", "bar" };
Array destinationArray = Array.CreateInstance(myType, myArray.Length);
Array.Copy(myArray, destinationArray, myArray.Length);
In this code, destinationArray
will be an instance of string[]
(or an array of whatever type myType
was).
Upvotes: 36
Reputation: 210755
You'd have to manually go through every object, get the most generic common type between them, and then create a new array of that type and copy the elements. There's no one-liner for this.
Upvotes: 1