How do I get the Array Item Type from Array Type in .net

后端 未结 3 1360
清酒与你
清酒与你 2020-12-09 00:54

Say I have an System.String[] type object. I can query the type object to determine if it is an array

Type t1 = typeof(System.String[]);
bool i         


        
相关标签:
3条回答
  • 2020-12-09 01:04

    Thanks to @psaxton comment pointing out the difference between Array and other collections. As an extension method:

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

    Usage:

    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
    
    0 讨论(0)
  • 2020-12-09 01:05

    You can use the instance method Type.GetElementType for this purpose.

    Type t2 = t1.GetElementType();
    

    [Returns] the type of the object encompassed or referred to by the current array, pointer, or reference type, or null if the current Type is not an array or a pointer, or is not passed by reference, or represents a generic type or a type parameter in the definition of a generic type or generic method.

    0 讨论(0)
  • 2020-12-09 01:22

    Thanks to @drzaus for his nice answer, but it can be compressed to a oneliner (plus check for nulls and IEnumerable type):

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

    Added null checkers to avoid exception, maybe I shouldn't (feel free to remove the Null Conditional Operators). Also added a filter so the function only works on collections, not any generic types.

    And bear in mind that this could also be fooled by implemented subclasses that change the subject of the collection and the implementor decided to move the collection's generic-type-argument to a later position.


    Converted answer for C#8 and nullability:

    public static Type GetEnumeratedType(this Type type) => 
            ((type?.GetElementType() ?? (typeof(IEnumerable).IsAssignableFrom(type)
                ? type.GenericTypeArguments.FirstOrDefault()
                : null))!;
    
    0 讨论(0)
提交回复
热议问题