1

I have a generic argument T which is an array in one particular case. Is it possible to cast array of objects to the array of typeof(T).GetElementType()? For example:

public TResult Execute<TResult>()// MyClass[] in this particular case
{
    var myArray = new List<object>() { ... }; //actual type of those objects is MyClass
    Type entityType = typeof(TResult).GetElementType(); //MyClass
    //casting to myArray to array of entityType 
    TResult result = ...;
    return result;    
} 
Roman Koliada
  • 4,286
  • 2
  • 30
  • 59

3 Answers3

2

This is not a good idea. You have no way to constrain TResult to an array, so with your current code, someone could call Excute<int> and get a runtime exception, yuck!

But, why constrain to an array to begin with? Just let the generic parameter be the type of the element itself:

public TResult[] Execute<TResult>()
{
    var myArray = ... 
    return myArray.Cast<TResult>().ToArray();
}

UPDATE: In response to your comments:

If Execute is an interface method you can not change, then you can do the following:

public static TResult Execute<TResult>()
{
    var myArray = new List<object>() { ... };
    var entityType = typeof(TResult).GetElementType();
    var outputArray = Array.CreateInstance(entityType, myArray.Count);
    Array.Copy(myArray.ToArray(), outputArray, myArray.Count); //note, this will only work with reference conversions. If user defined cast operators are involved, this method will fail.
    return (TResult)(object)outputArray;
}
InBetween
  • 32,319
  • 3
  • 50
  • 90
1

You can use the extension methods myArray.Cast<MyClass>().ToArray() to return an array of MyClass.

I think you mean to return TResult[] also:

public TResult[] Execute<TResult>()//MyClass[] in this particular case
{
    return myArray.Cast<MyClass>().ToArray();
}

You will need to add

using System.Linq;

In order to see these methods.

strongbutgood
  • 655
  • 7
  • 22
1

I agree with with InBetween that it's a bad idea, but I don't know your context and why you need this. But you can achieve it like that:

public TResult Execute<TResult>()// MyClass[] in this particular case
{
    var myArray = new List<object>() { ... }; //actual type of those objects is MyClass

    Type genericArgument = typeof(TResult);
    if (!genericArgument.IsArray)
       // what do you want to return now???

    Type elementType = genericArgument.GetElementType();

    MethodInfo cast = typeof(Enumerable).GetMethod("Cast").MakeGenericMethod(elementType);
    MethodInfo toarray = typeof(Enumerable).GetMethod("ToArray").MakeGenericMethod(elementType);

    object enumerable = cast.Invoke(null, new object[]{myArray});
    object array = toarray.Invoke(null, new object[]{enumerable});

    return (TResult)array;
}

This uses reflection to get the LINQ extension for the specific generic arguments. The question is: what should this method return if TResult is not an array. There seems to be a design flaw.

Mike Precup
  • 4,148
  • 21
  • 41
René Vogt
  • 43,056
  • 14
  • 77
  • 99
  • Thanks a lot! I've already have an implementation for non-array `TResult`(it's default case) so everything should work fine – Roman Koliada Aug 23 '16 at 08:43
  • I dont really think it needs to be this involved. The OP is basically asking for reference conversions (`object` -> *realUnderlyingType*). In that scenario, you can use `Array.Copy`. Check out my answer. – InBetween Aug 23 '16 at 08:55