Подтвердить что ты не робот

Как получить тип элемента массива из массива в .net

Скажем, у меня есть объект типа System.String[]. Я могу запросить объект типа, чтобы определить, является ли он массивом

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

Как мне получить объект типа элемента массива из t1

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

Ответ 1

Для этой цели вы можете использовать метод экземпляра Type.GetElementType.

Type t2 = t1.GetElementType();

[Возвращает] тип объекта, охватываемого или упомянутого текущим массивом, указателем или ссылочным типом, или null, если текущий тип не является массивом или указателем или не передается по ссылке или представляет собой общий тип или параметр типа в определении общего типа или общего метода.

Ответ 2

Спасибо @psaxton комментарий, указав разницу между массивами и другими коллекциями. В качестве метода расширения:

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

Ответ 3

Спасибо @drzaus за его хороший ответ, но он может быть сжат в oneliner (плюс проверьте тип null и IEnumerable):

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

Добавлены шашки null, чтобы избежать исключения, возможно, я не должен (не стесняйтесь удалить Null Conditional Operators). Также добавлен фильтр, поэтому функция работает только с коллекциями, а не с универсальными типами.

И имейте в виду, что это также может быть обмануто реализованными подклассами, которые меняют предмет коллекции, и разработчик решил перенести аргумент generic-type коллекции в более позднюю позицию.