如何从.net 中的 Array Type 获取 Array Item Type

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

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

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

Type t2 = ....; // should be typeof(System.String)
25990 次浏览

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

Type t2 = t1.GetElementType();

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

感谢@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

感谢 @ Drzaus为他的漂亮的 回答,但它可以压缩到一个线条(加上检查 nullIEnumerable类型) :

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

增加了 null检查器,以避免异常,也许我不应该(随时删除的 空条件运算符)。 还添加了一个过滤器,这样该函数只能在集合上工作,而不能在任何泛型类型上工作。

请记住,这也可能被改变集合主题的实现子类所愚弄,实现者决定将集合的泛型类型参数移到后面的位置。


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

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