Testing if object is of generic type in C#

C#.NetGenericsReflectionTypes

C# Problem Overview


I would like to perform a test 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 do I perform this test?

C# Solutions


Solution 1 - C#

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).

Solution 2 - C#

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.

Solution 3 - C#

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);

       
    }

Solution 4 - C#

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();

Solution 5 - C#

return list.GetType().IsGenericType;

Solution 6 - C#

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>>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRichbitsView Question on Stackoverflow
Solution 1 - C#mmxView Answer on Stackoverflow
Solution 2 - C#Jon SkeetView Answer on Stackoverflow
Solution 3 - C#Wiebe TijsmaView Answer on Stackoverflow
Solution 4 - C#David DesmaisonsView Answer on Stackoverflow
Solution 5 - C#Stan R.View Answer on Stackoverflow
Solution 6 - C#CodeRushView Answer on Stackoverflow