Testing if object is of generic type in C#
Solution 1
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
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
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
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();
Related videos on Youtube
Richbits
Updated on July 08, 2022Comments
-
Richbits almost 2 years
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?
-
Jon Skeet almost 15 yearsThat won't detect subtypes though. See my answer. It's also much harder for interfaces :(
-
SKJ about 13 yearsIt's correct for a different question. For this question, it's incorrect, as it only addresses (significantly less than) half of the problem.
-
SKJ about 13 yearsJust 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.
-
Jon Skeet about 13 years@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"
-
yoyo about 11 yearsStan 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.
-
Admin about 11 yearsWhat 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.
-
Jon Skeet about 11 years@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. -
Stan R. almost 11 yearspeople 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.
-
Kevin Cathcart over 9 years@JonSkeet: Why is it really tricky? My brief testing suggests that adding
foreach(var i in type.GetInterfaces()) if(i.IsGenericType && i.GetGenericTypeDefinition()==genericType) return true;
, right before the while loop appears to work just fine. Am I overlooking some odd edge case? -
Jon Skeet over 9 years@KevinCathcart: Hmm - you may be right. I seem to remember that there are some really nasty edge cases to consider, but I can't provoke any failures right now. Will edit the post to indicate this.
-
slawekwin over 7 yearscouldn't you replace the loop in
IsInstanceOfGenericType
with a call toIsAssignableFrom
instead of equality operator (==
)? -
Peter Ivan about 7 yearsNow you know that and you can improve your answer to be more specific and correct.
-
sjb-sjb over 5 yearsSee the answer below by Weibe Tijsma that handles interfaces as well.
-
Brendan Weinstein over 5 yearsThe call to GetGenericTypeDefinition will throw if it's not a generic type. Make sure you check that first.
-
mwryl over 3 years@JonSkeet you can detect subtypes using
list.GetType().BaseType
property. -
Jon Skeet over 3 years@MohammedLarabi: Yes, and that's exactly what my answer does, recursively...