>, will return {int}, the ...">

How can I get the "base" types in the "container type" in .NET?

I get a method which, when transmitted List<List<int>>, will return {int}, the transfer double[,]will be back {double}when the transfer Dictionary<string, byte[]>will be back {string, byte}and so on. Basically, it is about recursion by input type until the found type is no longer a "container type", and then reports this "base" type.

My initial assumption was to check the type of input to implement IEnumerable, but that didn't seem to work. I also made some trial and error with GetNestedTypes(), but this does not seem to be related. I ended up with the method below, which relies on instead ICollection. I have selected some rather strange types, and it seems to work; what I would like to know is that the method covers all types of containers or if it skips something (i.e. does this really work or are the results of my tests a “happy coincidence”?)

Many thanks.

EDIT (1): if passed, say, Dictionary<Foo, Bar>it's ok if the method returns {Foo, Bar}, regardless of the internal structure of these types (it doesn't need to go beyond that).

    public void GetPrimitiveTypes(Type inputType, ref List<Type> primitiveTypes)
    {
        if (inputType.IsGenericType)
            foreach (Type genericArg in inputType.GetGenericArguments())
                GetPrimitiveTypes(genericArg, ref primitiveTypes);

        if (inputType.IsArray)            
            GetPrimitiveTypes(inputType.GetElementType(), ref primitiveTypes);

        if (inputType.GetInterface("ICollection") == null)
            primitiveTypes.Add(inputType);
    }

EDIT (2): ( ). IsArray HasElementType ( ). ouside. , : (1) "" ICollection (2) , ICollection, , . , , , , . "" "" , "" , .

    public void GetPrimitiveTypes2(Type inputType, ref List<Type> primitiveTypes)
    {
        // Handle null
        if (inputType == null)
            throw new ArgumentNullException("inputType");

        // Leave pointers out
        if (inputType.IsPointer)
            throw new ArgumentException(message: "Pointer types are not supported", paramName: "inputType");

        // Option 1: type is generic
        if (inputType.IsGenericType)
        {
            foreach (Type genericArg in inputType.GetGenericArguments())
                GetPrimitiveTypes2(genericArg, ref primitiveTypes);

            return;
        }

        // Option 2: type has element type
        if (inputType.HasElementType)
        {
            GetPrimitiveTypes2(inputType.GetElementType(), ref primitiveTypes);
            return;
        }

        // Option 3: type is not a container
        // Remark: can't use IsPrimitive as it will be false for, say, type Foo
        if (inputType.GetInterface("ICollection") == null)
        {
            primitiveTypes.Add(inputType);
            return;
        }

        // Do options 1-3 above cover all cases?
        throw new ArgumentException(message: "Unhandled type", paramName: "inputType");
    }
+3
2

. , . .

    /// <summary>
    /// When given certain types such as those based on <see cref="T:Nullable`1"/>, <see cref="T:IEnumerable`1"/>,
    /// or <see cref="T:Array"/>, returns the element type associated with the input type.
    /// </summary>
    /// <remarks>
    /// For example, calling this method with Nullable(Of Boolean) would return Boolean. Passing Int32[] would
    /// return Int32, etc. All other types will return the input.
    /// </remarks>
    /// <param name="type">The a nullable type, array type, etc. whose element type you want to retrieve.</param>
    /// <returns>The type that the input type is based on.</returns>
    public static Type GetElementType( Type type )
    {

        ParameterValidation.ThrowIfNull( type, "type" );

        if ( type.IsGenericType ) {
            var typeArgs = type.GetGenericArguments( );
            if ( typeArgs.Length == 1 ) {
                return typeArgs[0];
            }   // if
        }   // if

        if ( type.HasElementType ) {
            return type.GetElementType( );
        }   // if

        if ( type.IsEnum ) {
            return Enum.GetUnderlyingType( type );
        }   // if

        return type;

    }
+1

, /:

public static Type GetElementType(Type type)
{
    if (type == null)
        throw new ArgumentNullException("type");

    if (type.HasElementType)
        return type.GetElementType();

    Type[] interfaces = type.GetInterfaces();
    foreach (Type t in interfaces)
    {
        if (t.IsGenericType)
        {
            Type generic = t.GetGenericTypeDefinition();
            if (generic == typeof(IEnumerable<>))
                return t.GetGenericArguments()[0];
        }
    }

    /* If you want to allow weakly typed collections (and just have element type
     * Object), you can uncomment the following:
     */
    //if (typeof(IEnumerable).IsAssignableFrom(type))
    //    return typeof(object);

    return null;
}

public static Type GetUnderlyingType(Type type)
{
    if (type == null)
        throw new ArgumentNullException("type");

    if (type.IsEnum)
        return type.GetEnumUnderlyingType();

    return Nullable.GetUnderlyingType(type);
}
0

Source: https://habr.com/ru/post/1730688/


All Articles