在运行时创建通用数组

时间:2012-09-24 06:12:30

标签: c# generics reflection

c#中有没有办法做这样的事情:

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

Goo返回object[],使用反射或其他什么?

2 个答案:

答案 0 :(得分:5)

您可以使用LINQ:

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

在您的示例中,您将object[]投射到T[],如果两种类型完全匹配,它们也会起作用:

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

例如,这将适用于以下情况:

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

然后像这样调用Foo:

Foo<string>();

答案 1 :(得分:0)

也许最简单和最可靠的方法是复制数组,逐个项目进行:

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

这是一个“unbox.any”,意思是(对JIT):

  • 如果castclass变成引用类型,请执行T(即参考保留类型检查)
  • 如果unbox原来是值类型,则
  • 执行T

引用类型的数组是协变,这意味着T[]可以代表作为object[]。因此,Goo() 的结果有可能实际上是T[]。我们可能还想测试一下:

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;
}

然而,一个令人烦恼的是我们现在有不同的语义 - 在某些情况下它是相同的数组,在某些情况下它被复制。如果我们 mutate 数组,这可能会有问题。