John Bustos
John Bustos

Reputation: 19544

Check if the object passed is IEnumerable<T> or a single value - Including T being a value types

In a part of my C# code, I have used the following code to check if an object passed in is a single value or implements IEnumerable<T> (T being string, double, int, etc - Never a complex object or class) :

Type type = paramValue.GetType();
if (type != typeof(string) && typeof(System.Collections.IEnumerable).IsAssignableFrom(type))
{
    var underlyingType = ((System.Collections.IEnumerable)paramValue).GetType().GetGenericArguments()[0];
}

And it has worked very well in all instances up until today when I passed in an int[] as I discovered to be an issue here.

So, what would the best way to get the underlying type of an IEnumerable that also accounts for value types be?

Thanks!!

Upvotes: 2

Views: 1277

Answers (3)

Tim Schmelter
Tim Schmelter

Reputation: 460098

You want to know the type and if it's an IEnumerable<T>(!= string) you want the T? For arrays you can use Type.GetElementType:

public static Type GetUnderlyingType(object paramValue)
{
    Type type = paramValue.GetType();
    var stringType = typeof(string);
    if (type == stringType)
        return stringType;
    else if (type.IsArray)
        type = type.GetElementType();
    else if (typeof(System.Collections.IEnumerable).IsAssignableFrom(type))
    {
        var genericArguments = ((System.Collections.IEnumerable) paramValue).GetType().GetGenericArguments();
        if(genericArguments.Length > 0)
            type = genericArguments[0];
    }
    return type;
}

Upvotes: 2

mm8
mm8

Reputation: 169200

As @Servy says, a non-generic IEnumerable sequence may contain elements of several different types.

If you only care about the first item in the sequence and assume that all other items are the same type, you could try something like this:

int[] paramValue = new int[] { 1, 2, 3 };
Type type = paramValue.GetType();
Type underlyingType;
if (type != typeof(string))
{
    System.Collections.IEnumerable e = paramValue as System.Collections.IEnumerable;
    if(e != null)
    {
        Type eType = e.GetType();
        if(eType.IsGenericType)
        {
            underlyingType = eType.GetType().GetGenericArguments()[0];
        }
        else
        {
            foreach(var item in e)
            {
                underlyingType = item.GetType();
                break;
            }
        }
    }
}

Note that, as an example, underlyingType will be int for the following paramValue though:

object[] paramValue = new object[] { 1, "a", "c" };

Upvotes: 0

Servy
Servy

Reputation: 203817

An IEnumerable doesn't have an underlying type, at least, not other than object. You know that each item in the sequence is an object, but you don't know any more than that. If you want to work with sequences of items where all of those items are of the same type (where that type isn't object then you need to work with IEnumerable<T>, not IEnumerable.

As it is, any given IEnumerable given to you might have a string and an int and a custom object, all in the same sequence, so there is no common type there other than object.

Upvotes: -1

Related Questions