188

I would like to perform a test to check if an object is of a generic type. I've tried the following without success:

public bool Test()
{
    List<int> list = new List<int>();
    return list.GetType() == typeof(List<>);
}

What am I doing wrong and how can I perform this test?

6 Answers 6

262

If you want to check if it's an instance of a generic type:

return list.GetType().IsGenericType;

If you want to check if it's a generic List<T>:

return list.GetType().GetGenericTypeDefinition() == typeof(List<>);

As Jon points out, this checks the exact type equivalence. Returning false doesn't necessarily mean list is List<T> returns false (i.e. the object cannot be assigned to a List<T> variable).

4
  • 14
    That won't detect subtypes though. See my answer. It's also much harder for interfaces :(
    – Jon Skeet
    Commented Jun 11, 2009 at 17:38
  • 1
    The call to GetGenericTypeDefinition will throw if it's not a generic type. Make sure you check that first.
    – Kilhoffer
    Commented Jan 16, 2019 at 15:57
  • @JonSkeet you can detect subtypes using list.GetType().BaseType property.
    – mwryl
    Commented Jan 21, 2021 at 6:37
  • 1
    @MohammedLarabi: Yes, and that's exactly what my answer does, recursively...
    – Jon Skeet
    Commented Jan 21, 2021 at 7:16
109

I assume that you don't just want to know if the type is generic, but if an object is an instance of a particular generic type, without knowing the type arguments.

It's not terribly simple, unfortunately. It's not too bad if the generic type is a class (as it is in this case) but it's harder for interfaces. Here's the code for a class:

using System;
using System.Collections.Generic;
using System.Reflection;

class Test
{
    static bool IsInstanceOfGenericType(Type genericType, object instance)
    {
        Type type = instance.GetType();
        while (type != null)
        {
            if (type.IsGenericType &&
                type.GetGenericTypeDefinition() == genericType)
            {
                return true;
            }
            type = type.BaseType;
        }
        return false;
    }

    static void Main(string[] args)
    {
        // True
        Console.WriteLine(IsInstanceOfGenericType(typeof(List<>),
                                                  new List<string>()));
        // False
        Console.WriteLine(IsInstanceOfGenericType(typeof(List<>),
                                                  new string[0]));
        // True
        Console.WriteLine(IsInstanceOfGenericType(typeof(List<>),
                                                  new SubList()));
        // True
        Console.WriteLine(IsInstanceOfGenericType(typeof(List<>),
                                                  new SubList<int>()));
    }

    class SubList : List<string>
    {
    }

    class SubList<T> : List<T>
    {
    }
}

EDIT: As noted in comments, this may work for interfaces:

foreach (var i in type.GetInterfaces())
{
    if (i.IsGenericType && i.GetGenericTypeDefinition() == genericType)
    {
        return true;
    }
}

I have a sneaking suspicion there may be some awkward edge cases around this, but I can't find one it fails for right now.

8
  • 2
    Just discovered a problem with this. It only goes down a single line of inheritance. If, along the way, you have a base with both a base class and the interface you're looking for, this goes down the class path only.
    – Groxx
    Commented Mar 18, 2011 at 23:41
  • 1
    @Groxx: True. I've just spotted that I do mention that in the answer though: "It's not too bad if the generic type is a class (as it is in this case) but it's harder for interfaces. Here's the code for a class"
    – Jon Skeet
    Commented Mar 19, 2011 at 7:31
  • 1
    What if you don't have a way to know <T>? Like, it might be int, or string, but you don't know that. This generates, it would seem, false negatives... so you don't have a T to use, you're just looking through properties of some object and one is a list. How do you know it is a list so you can unpeel it? By this I mean, you don't have a T anywhere nor a type to use. You could guess every type (is it List<int>? is it List<string>?) but what you want to know is IS THIS A A LIST? That question seems hard to answer.
    – user1086498
    Commented May 9, 2013 at 20:09
  • @RiverC: Yes, you're right - it is fairly hard to answer, for various reasons. If you're only talking about a class, it's not too bad... you can keep walking up the inheritance tree and see whether you hit List<T> in some form or other. If you include interfaces, it's really tricky.
    – Jon Skeet
    Commented May 9, 2013 at 20:14
  • 3
    couldn't you replace the loop in IsInstanceOfGenericType with a call to IsAssignableFrom instead of equality operator (==)?
    – slawekwin
    Commented Sep 21, 2016 at 10:44
13

These are my two favorite extension methods that cover most edge cases of generic type checking:

Works with:

  • Multiple (generic) interfaces
  • Multiple (generic) base classes
  • Has an overload that will 'out' the specific generic type if it returns true (see unit test for samples):

    public static bool IsOfGenericType(this Type typeToCheck, Type genericType)
    {
        Type concreteType;
        return typeToCheck.IsOfGenericType(genericType, out concreteType); 
    }
    
    public static bool IsOfGenericType(this Type typeToCheck, Type genericType, out Type concreteGenericType)
    {
        while (true)
        {
            concreteGenericType = null;
    
            if (genericType == null)
                throw new ArgumentNullException(nameof(genericType));
    
            if (!genericType.IsGenericTypeDefinition)
                throw new ArgumentException("The definition needs to be a GenericTypeDefinition", nameof(genericType));
    
            if (typeToCheck == null || typeToCheck == typeof(object))
                return false;
    
            if (typeToCheck == genericType)
            {
                concreteGenericType = typeToCheck;
                return true;
            }
    
            if ((typeToCheck.IsGenericType ? typeToCheck.GetGenericTypeDefinition() : typeToCheck) == genericType)
            {
                concreteGenericType = typeToCheck;
                return true;
            }
    
            if (genericType.IsInterface)
                foreach (var i in typeToCheck.GetInterfaces())
                    if (i.IsOfGenericType(genericType, out concreteGenericType))
                        return true;
    
            typeToCheck = typeToCheck.BaseType;
        }
    }
    

Here's a test to demonstrate the (basic) functionality:

 [Test]
    public void SimpleGenericInterfaces()
    {
        Assert.IsTrue(typeof(Table<string>).IsOfGenericType(typeof(IEnumerable<>)));
        Assert.IsTrue(typeof(Table<string>).IsOfGenericType(typeof(IQueryable<>)));

        Type concreteType;
        Assert.IsTrue(typeof(Table<string>).IsOfGenericType(typeof(IEnumerable<>), out concreteType));
        Assert.AreEqual(typeof(IEnumerable<string>), concreteType);

        Assert.IsTrue(typeof(Table<string>).IsOfGenericType(typeof(IQueryable<>), out concreteType));
        Assert.AreEqual(typeof(IQueryable<string>), concreteType);


    }
11

You can use shorter code using dynamic althougth this may be slower than pure reflection:

public static class Extension
{
    public static bool IsGenericList(this object o)
    {
       return IsGeneric((dynamic)o);
    }

    public static bool IsGeneric<T>(List<T> o)
    {
       return true;
    }

    public static bool IsGeneric( object o)
    {
        return false;
    }
}



var l = new List<int>();
l.IsGenericList().Should().BeTrue();

var o = new object();
o.IsGenericList().Should().BeFalse();
0
0
return list.GetType().IsGenericType;
4
  • 4
    It's correct for a different question. For this question, it's incorrect, as it only addresses (significantly less than) half of the problem.
    – Groxx
    Commented Mar 18, 2011 at 20:27
  • 2
    Stan R's answer does in fact answer the question as posed, but what the OP really meant was "Testing if object is of a particular generic type in C#", for which this answer is indeed incomplete.
    – yoyo
    Commented Mar 14, 2013 at 21:43
  • people are down-voting me because i answered the question in the context of "is a" generic type rather than "is of a" generic type. English is my 2nd languages and such language nuances pass me by often, to my defense the OP did not specifically ask to test against a specific type and in the title asks "is of" generic type...not sure why I deserve downvotes for an ambiguous question.
    – Stan R.
    Commented Jun 28, 2013 at 16:16
  • 2
    Now you know that and you can improve your answer to be more specific and correct.
    – Peter Ivan
    Commented Feb 10, 2017 at 15:26
0
public static string WhatIsMyType<T>()
{
    return typeof(T).NameWithGenerics();
}

public static string NameWithGenerics(this Type type)
{
    if (type == null)
        throw new ArgumentNullException(nameof(type));

    if (type.IsArray)
        return $"{type.GetElementType()?.Name}[]";

    if (!type.IsGenericType) 
        return type.Name;

    var name = type.GetGenericTypeDefinition().Name;
    var index = name.IndexOf('`');
    var newName = index == -1 ? name : name.Substring(0, index);
        
    var list = type.GetGenericArguments().Select(NameWithGenerics).ToList();
    return $"{newName}<{string.Join(",", list)}>";
}

Now test with this:

Console.WriteLine(WhatIsMyType<IEnumerable<string>>());
Console.WriteLine(WhatIsMyType<List<int>>());
Console.WriteLine(WhatIsMyType<IList<int>>());
Console.WriteLine(WhatIsMyType<List<ContentBlob>>());
Console.WriteLine(WhatIsMyType<int[]>());
Console.WriteLine(WhatIsMyType<ContentBlob>());
Console.WriteLine(WhatIsMyType<Dictionary<string, Dictionary<int, int>>>());

and you will get

IEnumerable<String>
List<Int32>
IList<Int32>
List<ContentBlob>
Int32[]
ContentBlob
Dictionary<String,Dictionary<Int32,Int32>>

Not the answer you're looking for? Browse other questions tagged or ask your own question.