872

Let's say I have a generic member in a class or method, like so:

public class Foo<T>
{
    public List<T> Bar { get; set; }
    
    public void Baz()
    {
        // get type of T
    }   
}

When I instantiate the class, the T becomes MyTypeObject1, so the class has a generic list property: List<MyTypeObject1>. The same applies to a generic method in a non-generic class:

public class Foo
{
    public void Bar<T>()
    {
        var baz = new List<T>();
        
        // get type of T
    }
}

I would like to know what type of objects the list of my class contains. So what type of T does the list property called Bar or the local variable baz contain?

I cannot do Bar[0].GetType(), because the list might contain zero elements. How can I do it?

18 Answers 18

911

If I understand correctly, your list has the same type parameter as the container class itself. If this is the case, then:

Type typeParameterType = typeof(T);

If you are in the lucky situation of having object as a type parameter, see Marc's answer.

Sign up to request clarification or add additional context in comments.

3 Comments

You can't use typeof() with a generic parameter, though.
@Reynevan Of course you can use typeof() with a generic parameter. Do you have any example where it wouldn't work? Or are you confusing type parameters and references?
@Luaan - I think he means you can't use typeof (x) when x is a variable - e.g. Type x=object.GetType();
595

(note: I'm assuming that all you know is object or IList or similar, and that the list could be any type at runtime)

If you know it is a List<T>, then:

Type type = abc.GetType().GetGenericArguments()[0];

Another option is to look at the indexer:

Type type = abc.GetType().GetProperty("Item").PropertyType;

Using new TypeInfo:

using System.Reflection;
// ...
var type = abc.GetType().GetTypeInfo().GenericTypeArguments[0];

12 Comments

Type type = abc.GetType().GetGenericArguments()[0]; ==> Out of bounds array index...
@Daok : then it isn't a List<T>
Give a try with BindingList<T>, our BindingListView<T> inherit from BindingList<T> and both I have try both of your option and it doesn't work. I might do something wrong... but I think this solution work for the type List<T> but not other type of list.
Type type = abc.GetType().GetProperty("Item").PropertyType; return BindingListView<MyObject> instead of MyObject...
@MarcGravell Indeed. I got it eventually. I was going through parent classes with a while loop to get the type, since the object's actual class was a child class of the generic type whose internal type I was after. I guess I went one step too far up the hierarchy, and it went from GenericType<ObjectType>, which was the one I needed, to GenericType<T>.
|
67

With the following extension method you can get away without reflection:

public static Type GetListType<T>(this List<T> _)
{
    return typeof(T);
}

Or more general:

public static Type GetEnumeratedType<T>(this IEnumerable<T> _)
{
    return typeof(T);
}

Usage:

List<string>        list    = new List<string> { "a", "b", "c" };
IEnumerable<string> strings = list;
IEnumerable<object> objects = list;

Type listType    = list.GetListType();           // string
Type stringsType = strings.GetEnumeratedType();  // string
Type objectsType = objects.GetEnumeratedType();  // BEWARE: object

2 Comments

This is only useful if you already know the type of T at compile time. In which case, you don't really need any code at all.
@recursive: It's useful if you're working with a list of an anonymous type.
34

Try

list.GetType().GetGenericArguments()

2 Comments

new List<int>().GetType().GetGenericArguments() returns System.Type[1] here with System.Int32 as entry
@Rauhotz the GetGenericArguments method returns an Array object of Type, of which you need to then parse out the position of the Generic Type you need. Such as Type<TKey, TValue>: you would need to GetGenericArguments()[0] to get TKey type and GetGenericArguments()[1] to get TValue type
29

If you don’t need the whole Type variable and just want to check the type, you can easily create a temporary variable and use the is operator.

T checkType = default(T);

if (checkType is MyClass)
{}

7 Comments

This should be the accepted answer, certainly the most performant.
Code Like a Pro :)
@EbrahimKarimi For sure :-)
It's completely wrong, instead, we can use ``` if (typeof(T) == typeof(Person)) ```
@VõQuangHòa I completely vote for your comment. your comments the right answer here
|
17

The following works for me. Where myList is some unknown kind of list.

IEnumerable myEnum = myList as IEnumerable;
Type entryType = myEnum.AsQueryable().ElementType;

4 Comments

I get an error that it requires a type argument (i.e. <T>)
Joseph and others, to get rid of the error it is in System.Collections.
Just the second line is needed for me. A List is already an implementation of IEnumerable, so the cast doesn't seem to add anything. But thanks, it's a good solution.
This worked for me as I have a ref type, that can and often does have no items - the other answers did not work
15

You can use this one for the return type of a generic list:

public string ListType<T>(T value)
{
    var valueType = value.GetType().GenericTypeArguments[0].FullName;
    return valueType;
}

Comments

9

The GetGenericArgument() method has to be set on the Base Type of your instance (whose class is a generic class myClass<T>). Otherwise, it returns a type[0].

Example:

Myclass<T> instance = new Myclass<T>();
Type[] listTypes = typeof(instance).BaseType.GetGenericArguments();

Comments

8

I use this extension method to accomplish something similar:

public static string GetFriendlyTypeName(this Type t)
{
    var typeName = t.Name.StripStartingWith("`");
    var genericArgs = t.GetGenericArguments();
    if (genericArgs.Length > 0)
    {
        typeName += "<";
        foreach (var genericArg in genericArgs)
        {
            typeName += genericArg.GetFriendlyTypeName() + ", ";
        }
        typeName = typeName.TrimEnd(',', ' ') + ">";
    }
    return typeName;
}

public static string StripStartingWith(this string s, string stripAfter)
{
    if (s == null)
    {
        return null;
    }
    var indexOf = s.IndexOf(stripAfter, StringComparison.Ordinal);
    if (indexOf > -1)
    {
        return s.Substring(0, indexOf);
    }
    return s;
}

You use it like this:

[TestMethod]
public void GetFriendlyTypeName_ShouldHandleReallyComplexTypes()
{
    typeof(Dictionary<string, Dictionary<string, object>>).GetFriendlyTypeName()
        .ShouldEqual("Dictionary<String, Dictionary<String, Object>>");
}

This isn't quite what you're looking for, but it's helpful in demonstrating the techniques involved.

1 Comment

An explanation would be in order. E.g., what is the gist of it? What is the idea? Please respond by editing your answer, not here in comments (without "Edit:", "Update:", or similar - the answer should appear as if it was written today).
8

Consider this:

I use it to export 20 typed lists by the same way:

private void Generate<T>()
{
    T item = (T)Activator.CreateInstance(typeof(T));

    ((T)item as DemomigrItemList).Initialize();

    Type type = ((T)item as DemomigrItemList).AsEnumerable().FirstOrDefault().GetType();
    if (type == null) 
        return;
    if (type != typeof(account)) // Account is listitem in List<account>
    {
        ((T)item as DemomigrItemList).CreateCSV(type);
    }
}

2 Comments

This doesn't work if T is an abstract superclass of the actual added objects. Not to mention, just new T(); would do the same thing as (T)Activator.CreateInstance(typeof(T));. It does require that you add where T : new() to the class/function definition, but if you want to make objects, that should be done anyway.
Also, you are calling GetType on a FirstOrDefault entry resulting in a potential null reference exception. If you are sure that it will return at least one item, why not use First instead?
6

You can get the type of "T" from any collection type that implements IEnumerable<T> with the following:

public static Type GetCollectionItemType(Type collectionType)
{
    var types = collectionType.GetInterfaces()
        .Where(x => x.IsGenericType 
            && x.GetGenericTypeDefinition() == typeof(IEnumerable<>))
        .ToArray();
    // Only support collections that implement IEnumerable<T> once.
    return types.Length == 1 ? types[0].GetGenericArguments()[0] : null;
}

Note that it doesn't support collection types that implement IEnumerable<T> twice, e.g.

public class WierdCustomType : IEnumerable<int>, IEnumerable<string> { ... }

I suppose you could return an array of types if you needed to support this...

Also, you might also want to cache the result per collection type if you're doing this a lot (e.g. in a loop).

Comments

1

Using 3dGrabber's solution:

public static T GetEnumeratedType<T>(this IEnumerable<T> _)
{
    return default(T);
}

//and now

var list = new Dictionary<string, int>();
var stronglyTypedVar = list.GetEnumeratedType();

Comments

1

To determine the type of objects contained in the list without relying on accessing an element (which might not exist), you can use reflection to obtain the type of the generic parameter T. Here's how you can do it:

For the generic class Foo:

public class Foo<T>
{
    public List<T> Bar { get; set; }
    
    public Type GetGenericType()
    {
        return typeof(T);
    }
}

And for the generic method in the non-generic class Foo:

  public class Foo
  {
      public Type GetGenericType<T>()
      {
          return typeof(T);
      }
  }

With these methods, you can retrieve the type of T used to instantiate the class or method:

 var foo = new Foo<MyTypeObject1>();
 Type typeOfTInFoo = foo.GetGenericType();

 // For the generic method
 var foo2 = new Foo();
 Type typeOfTInBar = foo2.GetGenericType<MyTypeObject1>();

Now, typeOfTInFoo and typeOfTInBar will hold the type MyTypeObject1, representing the type of objects contained in the List property or local variable.

Comments

0
public bool IsCollection<T>(T value){
  var valueType = value.GetType();
  return valueType.IsArray() || typeof(IEnumerable<object>).IsAssignableFrom(valueType) || typeof(IEnumerable<T>).IsAssignableFrom(valuetype);
}

2 Comments

This appears to address the question of whether the type is a list-y sort of thing, but the question is more about how to determine what generic type parameter a type that is known to be a List already was initialized with.
An explanation would be in order. E.g., what is the gist of it? What is the idea? Please respond by editing your answer, not here in comments (without "Edit:", "Update:", or similar - the answer should appear as if it was written today).
0

If you want to know a property's underlying type, try this:

propInfo.PropertyType.UnderlyingSystemType.GenericTypeArguments[0]

Comments

-1

This is how I did it:

internal static Type GetElementType(this Type type)
{
    // Use type.GenericTypeArguments if it exists
    if (type.GenericTypeArguments.Any())
        return type.GenericTypeArguments.First();

    return type.GetRuntimeProperty("Item").PropertyType);
}

Then call it like this:

var item = Activator.CreateInstance(iListType.GetElementType());

Or

var item = Activator.CreateInstance(Bar.GetType().GetElementType());

Comments

-1

try this.

if (typeof(T) == typeof(Person))

Comments

-9

Type:

type = list.AsEnumerable().SingleOrDefault().GetType();

3 Comments

This would throw a NullReferenceException if the list has no elements inside it for it to test against.
SingleOrDefault() also throws InvalidOperationException when there are two or more elements.
This answer is wrong, as pointed out correctly by \@rossisdead and \@devgeezer.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.