如何从.net中的数组类型获取数组项类型


71

说我有一个System.String[]类型对象。我可以查询类型对象以确定它是否是数组

Type t1 = typeof(System.String[]);
bool isAnArray = t1.IsArray; // should be true

但是如何从t1获取数组项的类型对象

Type t2 = ....; // should be typeof(System.String)

Answers:


115

您可以Type.GetElementType为此使用实例方法。

Type t2 = t1.GetElementType();

[返回]当前数组,指针或引用类型包含或引用的对象的类型;如果当前Type不是数组或指针,或者未通过引用传递,或表示泛型类型,则返回null泛型类型或泛型方法的定义中的类型参数。


Chrrrrrrrrrrrrrrrrrrrr Bro !. 太感谢了。
Preet Sangha

8
如最初提出的,这适用于数组。作为参考,包含类型的集合可以作为type.GetGenericArguments()[0]
psaxton

在您的链接的备注说:“这个方法返回nullArray类。” 因此,它可能仅适用于T[]表单。但是,在我对...Array产生的测试中似乎还不错Array.CreateInstance()
Ree先生

13

感谢@psaxton评论指出了Array与其他集合之间的区别。作为扩展方法:

public static class TypeHelperExtensions
{
    /// <summary>
    /// If the given <paramref name="type"/> is an array or some other collection
    /// comprised of 0 or more instances of a "subtype", get that type
    /// </summary>
    /// <param name="type">the source type</param>
    /// <returns></returns>
    public static Type GetEnumeratedType(this Type type)
    {
        // provided by Array
        var elType = type.GetElementType();
        if (null != elType) return elType;

        // otherwise provided by collection
        var elTypes = type.GetGenericArguments();
        if (elTypes.Length > 0) return elTypes[0];

        // otherwise is not an 'enumerated' type
        return null;
    }
}

用法:

typeof(Foo).GetEnumeratedType(); // null
typeof(Foo[]).GetEnumeratedType(); // Foo
typeof(List<Foo>).GetEnumeratedType(); // Foo
typeof(ICollection<Foo>).GetEnumeratedType(); // Foo
typeof(IEnumerable<Foo>).GetEnumeratedType(); // Foo

// some other oddities
typeof(HashSet<Foo>).GetEnumeratedType(); // Foo
typeof(Queue<Foo>).GetEnumeratedType(); // Foo
typeof(Stack<Foo>).GetEnumeratedType(); // Foo
typeof(Dictionary<int, Foo>).GetEnumeratedType(); // int
typeof(Dictionary<Foo, int>).GetEnumeratedType(); // Foo, seems to work against key

2
我在这里确实看到了一个小问题,那不是Colleciton或array的泛型类呢?我在公式中添加了if(type.IsArray || type.FullName.StartsWith(“ System.Collections”))。
安德烈·

@André的例子是什么?您的意思是自定义课程吗?因为实际上,如果它是枚举类型,则应该(?)继承自IEnumerable; 也许我对“收藏”的使用应该是“可枚举的”?
drzaus 2014年

@André不比较类型名称的字符串,而是检查是否typeof(IEnumerable).IsAssinableFrom(type)
Shimmy Weitzhandler'5

@drzaus他的意思是,如果我们检查一个通用类型,则不一定是IEnumerable,例如IObservable<T>,或其他。我将方法类型更改为GetGenericType
Shimmy Weitzhandler'5

2

由于@drzaus他很好的答案,但它可以被压缩到oneliner(加上检查nullS和IEnumerable类型):

public static Type GetEnumeratedType(this Type type) =>
   type?.GetElementType()
   ?? typeof(IEnumerable).IsAssignableFrom(type)
   ? type.GenericTypeArguments.FirstOrDefault()
   : null;

添加了null检查程序以避免异常,也许我不应该这样做(随意删除Null条件运算符)。还添加了一个过滤器,因此该功能仅适用于集合,不适用于任何泛型类型。

请记住,这也可能被更改子类的已实现子类所欺骗,并且实现者决定将集合的泛型类型参数移至更高位置。


C#8和可为空性的已转换答案:

public static Type GetEnumeratedType(this Type type) => 
        ((type?.GetElementType() ?? (typeof(IEnumerable).IsAssignableFrom(type)
            ? type.GenericTypeArguments.FirstOrDefault()
            : null))!;

发生了什么变化,逐字复制此代码,我收到此错误:“操作员'??' 不能应用于“类型”和“布尔”类型的操作数。(.NET核心C#8)
ΩmegaMan
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.