Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a generic array at runtime

Is there a way in c# to do something like this:

public void Foo<T>()
{
    T[] arr = Goo() as T[];
}

Where Goo returns an object[], Using reflection or whatever?

like image 782
Nir Smadar Avatar asked Sep 24 '12 06:09

Nir Smadar


People also ask

Can I create a generic array?

In Java, the generic array cannot be defined directly i.e. you cannot have a parameterized type assigned to an array reference. However, using object arrays and reflection features, you can simulate the generic array creation.

How do you initialize a generic array?

If you want to create an array of int values, then you only need to change the String type: int[] numbers = new int[4]; Knowing this, it seems that to initialize a generic array, you only need to type a generic like this: T[] names = new T[4];

Why we Cannot create a generic array in Java?

If generic array creation were legal, then compiler generated casts would correct the program at compile time but it can fail at runtime, which violates the core fundamental system of generic types.


2 Answers

You could use LINQ:

public void Foo<T>()
{
    T[] arr = Goo().OfType<T>().ToArray();
}

In your example you are casting the object[] to T[] which will also work if the two types match exactly:

public void Foo<T>()
{
    T[] arr = Goo() as T[];
    if (arr != null)
    {
        // use the array
    }
}

For example this will work in the following case:

public object[] Goo()
{
    return new string[] { "a", "b" };
}

and then calling Foo like this:

Foo<string>();
like image 88
Darin Dimitrov Avatar answered Oct 24 '22 16:10

Darin Dimitrov


Perhaps the simplest and most reliable approach is to copy the array, doing the cast item-by-item:

public void Foo<T>()
{
    T[] arr = Array.ConvertAll(Goo(), x => (T)x);
}

This is an "unbox.any", which means (to the JIT):

  • do a castclass (i.e. reference-preserving type-check) if T turns out to be reference-type
  • do an unbox if T turns out to be value-type

Arrays of reference-types are covariant, meaning that a T[] can be represented as an object[]. Because of this, there is a chance that the result of Goo() is actually a T[]. We might also want to test this:

public T[] Foo<T>()
{
    var tmp = Goo();
    T[] arr = tmp as T[];
    if(arr == null && tmp != null) {
        arr = Array.ConvertAll(Goo(), x => (T)x);
    }
    return arr;
}

One annoyance of this though is that we now have different semantics - in some cases it is the same array, in some cases it is copied. This could be problematic if we mutate the array.

like image 25
Marc Gravell Avatar answered Oct 24 '22 17:10

Marc Gravell