MHofer
MHofer

Reputation: 619

How can I find out if an object is a List of any type?

I'm working on a script that I can feed all sorts of objects and tell it to modify them in all sorts of ways. This works really well with many types, but I don't know how to go about handling Lists (and other Collections). This doesn't work:

List<Transform> transformList = new List<Transform>();

void MyFunction( object o ) {
    if( o.GetType() == typeof( int ) DoIntStuff(); //Easy
    else if( o.GetType() == typeof( Color ) DoColorStuff(); //Also Easy
    else if( o.GetType() == typeof( List<> ) ) DoListStuff(); //Not as easy :(
}

void Start() {
    MyFunction( transformList );
}

I can't do

typeof( List<T> )

because T doesn't exist in there of course.

typeof( List<object> ) 

does not work either.

So how can I find out if what I have is a list of any kind?

Upvotes: 0

Views: 1866

Answers (4)

hartmape
hartmape

Reputation: 553

If you just want to check if it's an List I would go with @Ali Ezzat Odeh approach and just check for

else if(o is IList) DoListStuff();

If you need to find out the containing type to handle lists with different elements you could try this extension method:

    public static class TypeExtensions 
    {
            /// <summary>
            /// Gets the inner type of the given type, if it is an Array or has generic arguments. 
            /// Otherwise NULL.
            /// </summary>
            public static Type GetInnerListType(this Type source)
            {
                Type innerType = null;

                if (source.IsArray)
                {
                    innerType = source.GetElementType();
                }
                else if (source.GetGenericArguments().Any())
                {
                    innerType = source.GetGenericArguments()[0];
                }

                return innerType;
            }
     }

You can use it like

else if(o.GetType().GetInnerListType() == typeof(Transform)) DoTransformListStuff();

The extension handles all kinds of lists, also arrays. In my opinion it would be better not to only look for types of List. This way you could replace your list with an alternate container like with an array for performance or with an observable collection if you're going into the UI. It will leave you with more design choices in the future and you can better adapt.

Upvotes: 1

Ali Ezzat Odeh
Ali Ezzat Odeh

Reputation: 2163

Why don't you test if object implements "IEnumerable" then check the type inside the collection(For genric collections) like the following:

IEnumerable tempList = o as IEnumerable;
        if (tempList != null)
        {
            IEnumerable<DumyClass> items = tempList.OfType<DumyClass>();

            if(items.Count() != 0)
            {
                //Then handle the list of the specific type as needed.
            }            
        }

If only List type is needed check for "IList" like the following :

IList tempList = o as IList;

        if (tempList != null)
        {
                //Then handle the list as needed.
        }

Hope this was useful.

Upvotes: 1

dbc
dbc

Reputation: 117323

Assuming you want to check that your type is/inherits from a List<T> for some T (rather than just implements IList<T> for some T) you could use the following extension method:

public static class TypeExtensions
{
    public static bool IsGenericList(this Type type)
    {
        return type.GetGenericListItemType() != null;
    }

    public static Type GetGenericListItemType(this Type type)
    {
        while (type != null)
        {
            if (type.IsGenericType)
            {
                var genType = type.GetGenericTypeDefinition();
                if (genType == typeof(List<>))
                    return type.GetGenericArguments()[0];
            }
            type = type.BaseType;
        }
        return null;
    }
}

Upvotes: 0

Abion47
Abion47

Reputation: 24846

As far as I know, there's no way to get the "List" part of a list object from the Type object. This is because according to the code, there is no "List" type, but actually a number of different generated types that correspond to every kind of generic that "List" receives throughout the course of your program. For example, if your program contained the following:

var a = new List<bool>();
var b = new List<int>();
var c = new List<char>();

Your compiled program will essentially contain the following classes, each with the T in its code replaced with the corresponding type:

List`1 // bool List
List`2 // int List
List`3 // char List

However, you could trick it a bit. Since the generic name will always follow the above pattern, you can use the name to perform your check:

var list = new List<int>();
var type = list.GetType();
bool isList = list.GetType().Name.Split('`')[0] == "List";

Upvotes: 0

Related Questions