How do I check if an object is an ICollection<T>? [duplicate] - c#

Assume the following type definitions:
public interface IFoo<T> : IBar<T> {}
public class Foo<T> : IFoo<T> {}
How do I find out whether the type Foo implements the generic interface IBar<T> when only the mangled type is available?

By using the answer from TcKs it can also be done with the following LINQ query:
bool isBar = foo.GetType().GetInterfaces().Any(x =>
x.IsGenericType &&
x.GetGenericTypeDefinition() == typeof(IBar<>));

You have to go up through the inheritance tree and find all the interfaces for each class in the tree, and compare typeof(IBar<>) with the result of calling Type.GetGenericTypeDefinition if the interface is generic. It's all a bit painful, certainly.
See this answer and these ones for more info and code.

public interface IFoo<T> : IBar<T> {}
public class Foo : IFoo<Foo> {}
var implementedInterfaces = typeof( Foo ).GetInterfaces();
foreach( var interfaceType in implementedInterfaces ) {
if ( false == interfaceType.IsGeneric ) { continue; }
var genericType = interfaceType.GetGenericTypeDefinition();
if ( genericType == typeof( IFoo<> ) ) {
// do something !
break;
}
}

As a helper method extension
public static bool Implements<I>(this Type type, I #interface) where I : class
{
if(((#interface as Type)==null) || !(#interface as Type).IsInterface)
throw new ArgumentException("Only interfaces can be 'implemented'.");
return (#interface as Type).IsAssignableFrom(type);
}
Example usage:
var testObject = new Dictionary<int, object>();
result = testObject.GetType().Implements(typeof(IDictionary<int, object>)); // true!

I'm using a slightly simpler version of #GenericProgrammers extension method:
public static bool Implements<TInterface>(this Type type) where TInterface : class {
var interfaceType = typeof(TInterface);
if (!interfaceType.IsInterface)
throw new InvalidOperationException("Only interfaces can be implemented.");
return (interfaceType.IsAssignableFrom(type));
}
Usage:
if (!featureType.Implements<IFeature>())
throw new InvalidCastException();

To tackle the type system completely, I think you need to handle recursion, e.g. IList<T> : ICollection<T> : IEnumerable<T>, without which you wouldn't know that IList<int> ultimately implements IEnumerable<>.
/// <summary>Determines whether a type, like IList<int>, implements an open generic interface, like
/// IEnumerable<>. Note that this only checks against *interfaces*.</summary>
/// <param name="candidateType">The type to check.</param>
/// <param name="openGenericInterfaceType">The open generic type which it may impelement</param>
/// <returns>Whether the candidate type implements the open interface.</returns>
public static bool ImplementsOpenGenericInterface(this Type candidateType, Type openGenericInterfaceType)
{
Contract.Requires(candidateType != null);
Contract.Requires(openGenericInterfaceType != null);
return
candidateType.Equals(openGenericInterfaceType) ||
(candidateType.IsGenericType && candidateType.GetGenericTypeDefinition().Equals(openGenericInterfaceType)) ||
candidateType.GetInterfaces().Any(i => i.IsGenericType && i.ImplementsOpenGenericInterface(openGenericInterfaceType));
}

In case you wanted an extension method that would support generic base types as well as interfaces, I've expanded sduplooy's answer:
public static bool InheritsFrom(this Type t1, Type t2)
{
if (null == t1 || null == t2)
return false;
if (null != t1.BaseType &&
t1.BaseType.IsGenericType &&
t1.BaseType.GetGenericTypeDefinition() == t2)
{
return true;
}
if (InheritsFrom(t1.BaseType, t2))
return true;
return
(t2.IsAssignableFrom(t1) && t1 != t2)
||
t1.GetInterfaces().Any(x =>
x.IsGenericType &&
x.GetGenericTypeDefinition() == t2);
}

You have to check against a constructed type of the generic interface.
You will have to do something like this:
foo is IBar<String>
because IBar<String> represents that constructed type. The reason you have to do this is because if T is undefined in your check, the compiler doesn't know if you mean IBar<Int32> or IBar<SomethingElse>.

First of all public class Foo : IFoo<T> {} does not compile because you need to specify a class instead of T, but assuming you do something like public class Foo : IFoo<SomeClass> {}
then if you do
Foo f = new Foo();
IBar<SomeClass> b = f as IBar<SomeClass>;
if(b != null) //derives from IBar<>
Blabla();

Method to check if the type inherits or implements a generic type:
public static bool IsTheGenericType(this Type candidateType, Type genericType)
{
return
candidateType != null && genericType != null &&
(candidateType.IsGenericType && candidateType.GetGenericTypeDefinition() == genericType ||
candidateType.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == genericType) ||
candidateType.BaseType != null && candidateType.BaseType.IsTheGenericType(genericType));
}

Try the following extension.
public static bool Implements(this Type #this, Type #interface)
{
if (#this == null || #interface == null) return false;
return #interface.GenericTypeArguments.Length>0
? #interface.IsAssignableFrom(#this)
: #this.GetInterfaces().Any(c => c.Name == #interface.Name);
}
To test it. create
public interface IFoo { }
public interface IFoo<T> : IFoo { }
public interface IFoo<T, M> : IFoo<T> { }
public class Foo : IFoo { }
public class Foo<T> : IFoo { }
public class Foo<T, M> : IFoo<T> { }
public class FooInt : IFoo<int> { }
public class FooStringInt : IFoo<string, int> { }
public class Foo2 : Foo { }
and the test method
public void Test()
{
Console.WriteLine(typeof(Foo).Implements(typeof(IFoo)));
Console.WriteLine(typeof(FooInt).Implements(typeof(IFoo)));
Console.WriteLine(typeof(FooInt).Implements(typeof(IFoo<>)));
Console.WriteLine(typeof(FooInt).Implements(typeof(IFoo<int>)));
Console.WriteLine(typeof(FooInt).Implements(typeof(IFoo<string>)));
Console.WriteLine(typeof(FooInt).Implements(typeof(IFoo<,>)));
Console.WriteLine(typeof(FooStringInt).Implements(typeof(IFoo<,>)));
Console.WriteLine(typeof(FooStringInt).Implements(typeof(IFoo<string,int>)));
Console.WriteLine(typeof(Foo<int,string>).Implements(typeof(IFoo<string>)));
}

var genericType = typeof(ITest<>);
Console.WriteLine(typeof(Test).GetInterfaces().Any(x => x.GetGenericTypeDefinition().Equals(genericType))); // prints: "True"
interface ITest<T> { };
class Test : ITest<string> { }
This worked for me.

You can add the below extension method:
public static TypeExtension
{
public static bool IsImplement<T>(this Type type)
{
return type.IsImplement(typeof(T));
}
public static bool IsImplement(this Type type, Type interfaceType)
{
if (!interfaceType.IsInterface)
throw new InvalidOperationException("Only interfaces can be implemented.");
return type.IsAssignableTo(interfaceType) ||
interfaceType.IsGenericType && type.GetInterfaces()
.Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == interfaceType.GetGenericTypeDefinition());
}
}

There shouldn't be anything wrong the following:
bool implementsGeneric = (anObject.Implements("IBar`1") != null);
For extra credit you could catch AmbiguousMatchException if you wanted to provide a specific generic-type-parameter with your IBar query.

Related

Check if class is a subclass of specific generic

I have the following classes:
public class HtSecurePage : UserControl, IDisposable
{
}
public class HtSecureInstancePage<T1> : HtSecurePage
{
}
public partial class NormalPage : HtSecurePage
{
}
public partial class InstancePage : HtSecureInstancePage<ZlsManager>
{
}
To check if NormalPage is a subClass of HtSecurePage I use the following pattern.
if (typeof(NormalPage).BaseType == typeof(HtSecurePage))
{
}
If I use this pattern against InstancePage, it is not working.
if (typeof(InstancePage).BaseType == typeof(HtSecureInstancePage<>))
{
}
I need to know if a Type is a direct subClass of HtSecurePage or HtSecureInstancePage<>. (It's important not to check against HtSecureInstancePage<ZlsManager>!) The Type T1 is unknown.
Below function check your class' sub-class the same type supplied class. If types is generic, check operation is executed over generic type definition.
Method usage
bool isInherited = CheckIsDirectlyInherited(typeof(TestAbstract), new[] {typeof(SecondLevelAbstractClass), typeof(FirstLevelAbstract)});
Method
bool CheckIsDirectlyInherited(Type obj, Type[] baseTypes)
{
if (obj.BaseType == null)
return false;
var objGenericDefinition = obj.BaseType;
if (objGenericDefinition.IsGenericType)
{
objGenericDefinition = objGenericDefinition.GetGenericTypeDefinition();
}
foreach (Type baseType in baseTypes)
{
var baseTypeDefinition = baseType;
if (baseTypeDefinition.IsGenericType)
baseTypeDefinition = baseType.GetGenericTypeDefinition();
if (objGenericDefinition == baseTypeDefinition)
return true;
}
return false;
}
is a direct subClass of HtSecurePage
I think you already know how to do it
Console.WriteLine(typeof(HtSecureInstancePage<ZlsManager>).BaseType == typeof(HtSecurePage));
is a direct subClass of HtSecureInstancePage<>
To check it you can use something like this:
static bool IsDirectSubclassOfRawGeneric(Type parent, Type toCheck)
{
return toCheck.BaseType.IsGenericType && parent == toCheck.BaseType.GetGenericTypeDefinition();
}
...
Console.WriteLine(IsDirectSubclassOfRawGeneric(typeof(HtSecureInstancePage<>), typeof(InstancePage)));

Get all sub classes of generic abstract base class

I have a generic base class and I eventually would have many derived classes.
I am trying to write a function which would return all these sub classes but everything I have tried so far has not worked.
public abstract class Index<T>
where T : class
{
public abstract string IndexName { get; }
public abstract string TypeName { get; }
public abstract Expression<Func<T, IConvertible>> IdFieldSelector { get; }
public string MakeSearchId(T item)
{
return ToSearchId(IdFieldSelector.Compile().Invoke(item));
}
public string MakeSearchId(IConvertible idValue)
{
return ToSearchId(idValue);
}
private static string ToSearchId(IConvertible idValue)
{
return idValue.ToString(CultureInfo.InvariantCulture);
}
}
sample subclass:
public class SurveyChangedIndex : Index<SurveyChanged>
{
public override string IndexName => "reviews";
public override string TypeName => "review";
public override Expression<Func<SurveyChanged, IConvertible>> IdFieldSelector => sc => sc.SurveyResponseId;
}
sample function:
var indexBase = typeof(Index<>);
var indexes = Assembly.GetAssembly(indexBase)
.GetTypes()
.Where(type =>
type != indexBase &&
!type.IsInterface &&
!type.IsAbstract &&
type.BaseType == indexBase)
.ToList();
You can do the following (C# 7 syntax follows):
public static IEnumerable<Type> GetAllDescendantsOf(
this Assembly assembly,
Type genericTypeDefinition)
{
IEnumerable<Type> GetAllAscendants(Type t)
{
var current = t;
while (current.BaseType != typeof(object))
{
yield return current.BaseType;
current = current.BaseType;
}
}
if (assembly == null)
throw new ArgumentNullException(nameof(assembly));
if (genericTypeDefinition == null)
throw new ArgumentNullException(nameof(genericTypeDefinition));
if (!genericTypeDefinition.IsGenericTypeDefinition)
throw new ArgumentException(
"Specified type is not a valid generic type definition.",
nameof(genericTypeDefinition));
return assembly.GetTypes()
.Where(t => GetAllAscendants(t).Any(d =>
d.IsGenericType &&
d.GetGenericTypeDefinition()
.Equals(genericTypeDefinition)));
}
This will return any type that inherits directly or indirectly from the specified generic type definition.
In the following scenario:
class Base { }
class Base<T>: Base { }
class Foo : Base<int> { }
class Bar : Base<string> { }
class Frob : Bar { }
class FooBar: Base { };
var genericTypeDefinition = typeof(Base<>);
var types = Assembly.GetExecutingAssembly()
.GetAllDescendantsOf(genericTypeDefinition)));
GetAllDescendantsOf will output Foo, Bar and Frob.
This should solve your code:
var indexes = Assembly.GetAssembly(indexBase)
.GetTypes()
.Where(type =>
type != indexBase &&
!type.IsInterface &&
!type.IsAbstract &&
type.BaseType.IsAssignableFrom(indexBase))
.ToList();
This worked for me:
var indexes = Assembly.GetAssembly(indexBase)
.GetTypes()
.Where(IsIndexType)
.ToArray();
with
private bool IsIndexType(Type type)
{
var indexDefinition = typeof(Index<>).GetGenericTypeDefinition();
return !type.IsAbstract
&& type.IsClass
&& type.BaseType is not null
&& type.BaseType.IsGenericType
&& type.BaseType.GetGenericTypeDefinition() == indexDefinition;
}

Obtaining a list of subtypes of generic class

I have a generic class with many subtypes:
public abstract class MyClass<T> : MyBaseClass where T : class
{...}
public class MySubClassA : MyClass<A>
{...}
public class MySubClassB : MyClass<B>
{...}
Is there an easy way to search for subclasses of MyClass and obtain an IEnumerable<Type> containing MySubClassA and MySubClassB?
I have used this method before, but I am not sure how to adapt it for use with generics:
public static IEnumerable<Type> GetSubTypesOf(Type t, bool baseAssemblyOnly = false)
{
List<Type> types = new List<Type>();
Assembly[] searchAssemblies = baseAssemblyOnly
? new[] { Assembly.GetAssembly(t) }
: AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly a in searchAssemblies)
{
types.AddRange(a.GetTypes()
.Where(myType => myType.IsClass
&& !myType.IsAbstract
&& myType.IsSubclassOf(t)));
}
return types;
}
This is a bit complicated since you have to search the base types of a type to find one which matches the open generic type definition of MyClass<>. You can define a couple of helper methods:
public static IEnumerable<Type> BaseTypesOf(Type t)
{
while (t != null)
{
yield return t;
t = t.BaseType;
}
}
public static Type FindGenericBaseTypeOf(Type t, Type openType)
{
return BaseTypesOf(t)
.FirstOrDefault(bt => bt.IsGenericType && bt.GetGenericTypeDefinition() == openType);
}
then you can apply them to the incoming sequence of types to search e.g.
var types = Assembly.GetExecutingAssembly().GetTypes()
.Where(t => t.IsClass && !t.IsAbstract)
.Select(t => new { Type = t, GenericBase = FindGenericBaseTypeOf(t, typeof(MyClass<>)) })
.Where(ts => ts.GenericBase != null)
.Select(ts => ts.GenericBase.GetGenericArguments().First())
.ToArray();
The problem is that when you pass typeof(MyClass<>) for the t parameter, you are not passing an instantiated generic type, but a generic type definition. This means that none of your classes would respond to IsSubclassOf(t).
You can fix your code as follows:
List<Type> types = searchAssemblies
.SelectMany(a =>
a.GetTypes()
.Where(myType => myType.IsClass && !myType.IsAbstract && HasGenericBase(myType, t))
).ToList();
...
private static bool HasGenericBase(Type myType, Type t) {
Debug.Assert(t.IsGenericTypeDefinition);
while (myType != typeof(object)) {
if (myType.IsGenericType && myType.GetGenericTypeDefinition() == t) {
return true;
}
myType = myType.BaseType;
}
return false;
}

How to use 'is' operator with a generic class [duplicate]

I have a generic class in my project with derived classes.
public class GenericClass<T> : GenericInterface<T>
{
}
public class Test : GenericClass<SomeType>
{
}
Is there any way to find out if a Type object is derived from GenericClass?
t.IsSubclassOf(typeof(GenericClass<>))
does not work.
Try this code
static bool IsSubclassOfRawGeneric(Type generic, Type toCheck) {
while (toCheck != null && toCheck != typeof(object)) {
var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
if (generic == cur) {
return true;
}
toCheck = toCheck.BaseType;
}
return false;
}
(Reposted due to a massive rewrite)
JaredPar's code answer is fantastic, but I have a tip that would make it unnecessary if your generic types are not based on value type parameters. I was hung up on why the "is" operator would not work, so I have also documented the results of my experimentation for future reference. Please enhance this answer to further enhance its clarity.
TIP:
If you make certain that your GenericClass implementation inherits from an abstract non-generic base class such as GenericClassBase, you could ask the same question without any trouble at all like this:
typeof(Test).IsSubclassOf(typeof(GenericClassBase))
IsSubclassOf()
My testing indicates that IsSubclassOf() does not work on parameterless generic types such as
typeof(GenericClass<>)
whereas it will work with
typeof(GenericClass<SomeType>)
Therefore the following code will work for any derivation of GenericClass<>, assuming you are willing to test based on SomeType:
typeof(Test).IsSubclassOf(typeof(GenericClass<SomeType>))
The only time I can imagine that you would want to test by GenericClass<> is in a plug-in framework scenario.
Thoughts on the "is" operator
At design-time C# does not allow the use of parameterless generics because they are essentially not a complete CLR type at that point. Therefore, you must declare generic variables with parameters, and that is why the "is" operator is so powerful for working with objects. Incidentally, the "is" operator also can not evaluate parameterless generic types.
The "is" operator will test the entire inheritance chain, including interfaces.
So, given an instance of any object, the following method will do the trick:
bool IsTypeof<T>(object t)
{
return (t is T);
}
This is sort of redundant, but I figured I would go ahead and visualize it for everybody.
Given
var t = new Test();
The following lines of code would return true:
bool test1 = IsTypeof<GenericInterface<SomeType>>(t);
bool test2 = IsTypeof<GenericClass<SomeType>>(t);
bool test3 = IsTypeof<Test>(t);
On the other hand, if you want something specific to GenericClass, you could make it more specific, I suppose, like this:
bool IsTypeofGenericClass<SomeType>(object t)
{
return (t is GenericClass<SomeType>);
}
Then you would test like this:
bool test1 = IsTypeofGenericClass<SomeType>(t);
I worked through some of these samples and found they were lacking in some cases. This version works with all kinds of generics: types, interfaces and type definitions thereof.
public static bool InheritsOrImplements(this Type child, Type parent)
{
parent = ResolveGenericTypeDefinition(parent);
var currentChild = child.IsGenericType
? child.GetGenericTypeDefinition()
: child;
while (currentChild != typeof (object))
{
if (parent == currentChild || HasAnyInterfaces(parent, currentChild))
return true;
currentChild = currentChild.BaseType != null
&& currentChild.BaseType.IsGenericType
? currentChild.BaseType.GetGenericTypeDefinition()
: currentChild.BaseType;
if (currentChild == null)
return false;
}
return false;
}
private static bool HasAnyInterfaces(Type parent, Type child)
{
return child.GetInterfaces()
.Any(childInterface =>
{
var currentInterface = childInterface.IsGenericType
? childInterface.GetGenericTypeDefinition()
: childInterface;
return currentInterface == parent;
});
}
private static Type ResolveGenericTypeDefinition(Type parent)
{
var shouldUseGenericType = true;
if (parent.IsGenericType && parent.GetGenericTypeDefinition() != parent)
shouldUseGenericType = false;
if (parent.IsGenericType && shouldUseGenericType)
parent = parent.GetGenericTypeDefinition();
return parent;
}
Here are the unit tests also:
protected interface IFooInterface
{
}
protected interface IGenericFooInterface<T>
{
}
protected class FooBase
{
}
protected class FooImplementor
: FooBase, IFooInterface
{
}
protected class GenericFooBase
: FooImplementor, IGenericFooInterface<object>
{
}
protected class GenericFooImplementor<T>
: FooImplementor, IGenericFooInterface<T>
{
}
[Test]
public void Should_inherit_or_implement_non_generic_interface()
{
Assert.That(typeof(FooImplementor)
.InheritsOrImplements(typeof(IFooInterface)), Is.True);
}
[Test]
public void Should_inherit_or_implement_generic_interface()
{
Assert.That(typeof(GenericFooBase)
.InheritsOrImplements(typeof(IGenericFooInterface<>)), Is.True);
}
[Test]
public void Should_inherit_or_implement_generic_interface_by_generic_subclass()
{
Assert.That(typeof(GenericFooImplementor<>)
.InheritsOrImplements(typeof(IGenericFooInterface<>)), Is.True);
}
[Test]
public void Should_inherit_or_implement_generic_interface_by_generic_subclass_not_caring_about_generic_type_parameter()
{
Assert.That(new GenericFooImplementor<string>().GetType()
.InheritsOrImplements(typeof(IGenericFooInterface<>)), Is.True);
}
[Test]
public void Should_not_inherit_or_implement_generic_interface_by_generic_subclass_not_caring_about_generic_type_parameter()
{
Assert.That(new GenericFooImplementor<string>().GetType()
.InheritsOrImplements(typeof(IGenericFooInterface<int>)), Is.False);
}
[Test]
public void Should_inherit_or_implement_non_generic_class()
{
Assert.That(typeof(FooImplementor)
.InheritsOrImplements(typeof(FooBase)), Is.True);
}
[Test]
public void Should_inherit_or_implement_any_base_type()
{
Assert.That(typeof(GenericFooImplementor<>)
.InheritsOrImplements(typeof(FooBase)), Is.True);
}
It seems to me that this implementation works in more cases (generic class and interface with or without initiated parameters, regardless of the number of child and parameters):
public static class ReflexionExtension
{
public static bool IsSubClassOfGeneric(this Type child, Type parent)
{
if (child == parent)
return false;
if (child.IsSubclassOf(parent))
return true;
var parameters = parent.GetGenericArguments();
var isParameterLessGeneric = !(parameters != null && parameters.Length > 0 &&
((parameters[0].Attributes & TypeAttributes.BeforeFieldInit) == TypeAttributes.BeforeFieldInit));
while (child != null && child != typeof(object))
{
var cur = GetFullTypeDefinition(child);
if (parent == cur || (isParameterLessGeneric && cur.GetInterfaces().Select(i => GetFullTypeDefinition(i)).Contains(GetFullTypeDefinition(parent))))
return true;
else if (!isParameterLessGeneric)
if (GetFullTypeDefinition(parent) == cur && !cur.IsInterface)
{
if (VerifyGenericArguments(GetFullTypeDefinition(parent), cur))
if (VerifyGenericArguments(parent, child))
return true;
}
else
foreach (var item in child.GetInterfaces().Where(i => GetFullTypeDefinition(parent) == GetFullTypeDefinition(i)))
if (VerifyGenericArguments(parent, item))
return true;
child = child.BaseType;
}
return false;
}
private static Type GetFullTypeDefinition(Type type)
{
return type.IsGenericType ? type.GetGenericTypeDefinition() : type;
}
private static bool VerifyGenericArguments(Type parent, Type child)
{
Type[] childArguments = child.GetGenericArguments();
Type[] parentArguments = parent.GetGenericArguments();
if (childArguments.Length == parentArguments.Length)
for (int i = 0; i < childArguments.Length; i++)
if (childArguments[i].Assembly != parentArguments[i].Assembly || childArguments[i].Name != parentArguments[i].Name || childArguments[i].Namespace != parentArguments[i].Namespace)
if (!childArguments[i].IsSubclassOf(parentArguments[i]))
return false;
return true;
}
}
Here are my 70 76 test cases:
[TestMethod]
public void IsSubClassOfGenericTest()
{
Assert.IsTrue(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(BaseGeneric<>)), " 1");
Assert.IsFalse(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(WrongBaseGeneric<>)), " 2");
Assert.IsTrue(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(IBaseGeneric<>)), " 3");
Assert.IsFalse(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(IWrongBaseGeneric<>)), " 4");
Assert.IsTrue(typeof(IChildGeneric).IsSubClassOfGeneric(typeof(IBaseGeneric<>)), " 5");
Assert.IsFalse(typeof(IWrongBaseGeneric<>).IsSubClassOfGeneric(typeof(ChildGeneric2<>)), " 6");
Assert.IsTrue(typeof(ChildGeneric2<>).IsSubClassOfGeneric(typeof(BaseGeneric<>)), " 7");
Assert.IsTrue(typeof(ChildGeneric2<Class1>).IsSubClassOfGeneric(typeof(BaseGeneric<>)), " 8");
Assert.IsTrue(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(BaseGeneric<Class1>)), " 9");
Assert.IsFalse(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(WrongBaseGeneric<Class1>)), "10");
Assert.IsTrue(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(IBaseGeneric<Class1>)), "11");
Assert.IsFalse(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(IWrongBaseGeneric<Class1>)), "12");
Assert.IsTrue(typeof(IChildGeneric).IsSubClassOfGeneric(typeof(IBaseGeneric<Class1>)), "13");
Assert.IsFalse(typeof(BaseGeneric<Class1>).IsSubClassOfGeneric(typeof(ChildGeneric2<Class1>)), "14");
Assert.IsTrue(typeof(ChildGeneric2<Class1>).IsSubClassOfGeneric(typeof(BaseGeneric<Class1>)), "15");
Assert.IsFalse(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(ChildGeneric)), "16");
Assert.IsFalse(typeof(IChildGeneric).IsSubClassOfGeneric(typeof(IChildGeneric)), "17");
Assert.IsFalse(typeof(IBaseGeneric<>).IsSubClassOfGeneric(typeof(IChildGeneric2<>)), "18");
Assert.IsTrue(typeof(IChildGeneric2<>).IsSubClassOfGeneric(typeof(IBaseGeneric<>)), "19");
Assert.IsTrue(typeof(IChildGeneric2<Class1>).IsSubClassOfGeneric(typeof(IBaseGeneric<>)), "20");
Assert.IsFalse(typeof(IBaseGeneric<Class1>).IsSubClassOfGeneric(typeof(IChildGeneric2<Class1>)), "21");
Assert.IsTrue(typeof(IChildGeneric2<Class1>).IsSubClassOfGeneric(typeof(IBaseGeneric<Class1>)), "22");
Assert.IsFalse(typeof(IBaseGeneric<Class1>).IsSubClassOfGeneric(typeof(BaseGeneric<Class1>)), "23");
Assert.IsTrue(typeof(BaseGeneric<Class1>).IsSubClassOfGeneric(typeof(IBaseGeneric<Class1>)), "24");
Assert.IsFalse(typeof(IBaseGeneric<>).IsSubClassOfGeneric(typeof(BaseGeneric<>)), "25");
Assert.IsTrue(typeof(BaseGeneric<>).IsSubClassOfGeneric(typeof(IBaseGeneric<>)), "26");
Assert.IsTrue(typeof(BaseGeneric<Class1>).IsSubClassOfGeneric(typeof(IBaseGeneric<>)), "27");
Assert.IsFalse(typeof(IBaseGeneric<Class1>).IsSubClassOfGeneric(typeof(IBaseGeneric<Class1>)), "28");
Assert.IsTrue(typeof(BaseGeneric2<Class1>).IsSubClassOfGeneric(typeof(IBaseGeneric<Class1>)), "29");
Assert.IsFalse(typeof(IBaseGeneric<>).IsSubClassOfGeneric(typeof(BaseGeneric2<>)), "30");
Assert.IsTrue(typeof(BaseGeneric2<>).IsSubClassOfGeneric(typeof(IBaseGeneric<>)), "31");
Assert.IsTrue(typeof(BaseGeneric2<Class1>).IsSubClassOfGeneric(typeof(IBaseGeneric<>)), "32");
Assert.IsTrue(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(BaseGenericA<,>)), "33");
Assert.IsFalse(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(WrongBaseGenericA<,>)), "34");
Assert.IsTrue(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(IBaseGenericA<,>)), "35");
Assert.IsFalse(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(IWrongBaseGenericA<,>)), "36");
Assert.IsTrue(typeof(IChildGenericA).IsSubClassOfGeneric(typeof(IBaseGenericA<,>)), "37");
Assert.IsFalse(typeof(IWrongBaseGenericA<,>).IsSubClassOfGeneric(typeof(ChildGenericA2<,>)), "38");
Assert.IsTrue(typeof(ChildGenericA2<,>).IsSubClassOfGeneric(typeof(BaseGenericA<,>)), "39");
Assert.IsTrue(typeof(ChildGenericA2<ClassA, ClassB>).IsSubClassOfGeneric(typeof(BaseGenericA<,>)), "40");
Assert.IsTrue(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(BaseGenericA<ClassA, ClassB>)), "41");
Assert.IsFalse(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(WrongBaseGenericA<ClassA, ClassB>)), "42");
Assert.IsTrue(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(IBaseGenericA<ClassA, ClassB>)), "43");
Assert.IsFalse(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(IWrongBaseGenericA<ClassA, ClassB>)), "44");
Assert.IsTrue(typeof(IChildGenericA).IsSubClassOfGeneric(typeof(IBaseGenericA<ClassA, ClassB>)), "45");
Assert.IsFalse(typeof(BaseGenericA<ClassA, ClassB>).IsSubClassOfGeneric(typeof(ChildGenericA2<ClassA, ClassB>)), "46");
Assert.IsTrue(typeof(ChildGenericA2<ClassA, ClassB>).IsSubClassOfGeneric(typeof(BaseGenericA<ClassA, ClassB>)), "47");
Assert.IsFalse(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(ChildGenericA)), "48");
Assert.IsFalse(typeof(IChildGenericA).IsSubClassOfGeneric(typeof(IChildGenericA)), "49");
Assert.IsFalse(typeof(IBaseGenericA<,>).IsSubClassOfGeneric(typeof(IChildGenericA2<,>)), "50");
Assert.IsTrue(typeof(IChildGenericA2<,>).IsSubClassOfGeneric(typeof(IBaseGenericA<,>)), "51");
Assert.IsTrue(typeof(IChildGenericA2<ClassA, ClassB>).IsSubClassOfGeneric(typeof(IBaseGenericA<,>)), "52");
Assert.IsFalse(typeof(IBaseGenericA<ClassA, ClassB>).IsSubClassOfGeneric(typeof(IChildGenericA2<ClassA, ClassB>)), "53");
Assert.IsTrue(typeof(IChildGenericA2<ClassA, ClassB>).IsSubClassOfGeneric(typeof(IBaseGenericA<ClassA, ClassB>)), "54");
Assert.IsFalse(typeof(IBaseGenericA<ClassA, ClassB>).IsSubClassOfGeneric(typeof(BaseGenericA<ClassA, ClassB>)), "55");
Assert.IsTrue(typeof(BaseGenericA<ClassA, ClassB>).IsSubClassOfGeneric(typeof(IBaseGenericA<ClassA, ClassB>)), "56");
Assert.IsFalse(typeof(IBaseGenericA<,>).IsSubClassOfGeneric(typeof(BaseGenericA<,>)), "57");
Assert.IsTrue(typeof(BaseGenericA<,>).IsSubClassOfGeneric(typeof(IBaseGenericA<,>)), "58");
Assert.IsTrue(typeof(BaseGenericA<ClassA, ClassB>).IsSubClassOfGeneric(typeof(IBaseGenericA<,>)), "59");
Assert.IsFalse(typeof(IBaseGenericA<ClassA, ClassB>).IsSubClassOfGeneric(typeof(IBaseGenericA<ClassA, ClassB>)), "60");
Assert.IsTrue(typeof(BaseGenericA2<ClassA, ClassB>).IsSubClassOfGeneric(typeof(IBaseGenericA<ClassA, ClassB>)), "61");
Assert.IsFalse(typeof(IBaseGenericA<,>).IsSubClassOfGeneric(typeof(BaseGenericA2<,>)), "62");
Assert.IsTrue(typeof(BaseGenericA2<,>).IsSubClassOfGeneric(typeof(IBaseGenericA<,>)), "63");
Assert.IsTrue(typeof(BaseGenericA2<ClassA, ClassB>).IsSubClassOfGeneric(typeof(IBaseGenericA<,>)), "64");
Assert.IsFalse(typeof(BaseGenericA2<ClassB, ClassA>).IsSubClassOfGeneric(typeof(IBaseGenericA<ClassA, ClassB>)), "65");
Assert.IsFalse(typeof(BaseGenericA<ClassB, ClassA>).IsSubClassOfGeneric(typeof(ChildGenericA2<ClassA, ClassB>)), "66");
Assert.IsFalse(typeof(BaseGenericA2<ClassB, ClassA>).IsSubClassOfGeneric(typeof(BaseGenericA<ClassA, ClassB>)), "67");
Assert.IsTrue(typeof(ChildGenericA3<ClassA, ClassB>).IsSubClassOfGeneric(typeof(BaseGenericB<ClassA, ClassB, ClassC>)), "68");
Assert.IsTrue(typeof(ChildGenericA4<ClassA, ClassB>).IsSubClassOfGeneric(typeof(IBaseGenericB<ClassA, ClassB, ClassC>)), "69");
Assert.IsFalse(typeof(ChildGenericA3<ClassB, ClassA>).IsSubClassOfGeneric(typeof(BaseGenericB<ClassA, ClassB, ClassC>)), "68-2");
Assert.IsTrue(typeof(ChildGenericA3<ClassA, ClassB2>).IsSubClassOfGeneric(typeof(BaseGenericB<ClassA, ClassB, ClassC>)), "68-3");
Assert.IsFalse(typeof(ChildGenericA3<ClassB2, ClassA>).IsSubClassOfGeneric(typeof(BaseGenericB<ClassA, ClassB, ClassC>)), "68-4");
Assert.IsFalse(typeof(ChildGenericA4<ClassB, ClassA>).IsSubClassOfGeneric(typeof(IBaseGenericB<ClassA, ClassB, ClassC>)), "69-2");
Assert.IsTrue(typeof(ChildGenericA4<ClassA, ClassB2>).IsSubClassOfGeneric(typeof(IBaseGenericB<ClassA, ClassB, ClassC>)), "69-3");
Assert.IsFalse(typeof(ChildGenericA4<ClassB2, ClassA>).IsSubClassOfGeneric(typeof(IBaseGenericB<ClassA, ClassB, ClassC>)), "69-4");
Assert.IsFalse(typeof(bool).IsSubClassOfGeneric(typeof(IBaseGenericB<ClassA, ClassB, ClassC>)), "70");
}
Classes and interfaces for testing :
public class Class1 { }
public class BaseGeneric<T> : IBaseGeneric<T> { }
public class BaseGeneric2<T> : IBaseGeneric<T>, IInterfaceBidon { }
public interface IBaseGeneric<T> { }
public class ChildGeneric : BaseGeneric<Class1> { }
public interface IChildGeneric : IBaseGeneric<Class1> { }
public class ChildGeneric2<Class1> : BaseGeneric<Class1> { }
public interface IChildGeneric2<Class1> : IBaseGeneric<Class1> { }
public class WrongBaseGeneric<T> { }
public interface IWrongBaseGeneric<T> { }
public interface IInterfaceBidon { }
public class ClassA { }
public class ClassB { }
public class ClassC { }
public class ClassB2 : ClassB { }
public class BaseGenericA<T, U> : IBaseGenericA<T, U> { }
public class BaseGenericB<T, U, V> { }
public interface IBaseGenericB<ClassA, ClassB, ClassC> { }
public class BaseGenericA2<T, U> : IBaseGenericA<T, U>, IInterfaceBidonA { }
public interface IBaseGenericA<T, U> { }
public class ChildGenericA : BaseGenericA<ClassA, ClassB> { }
public interface IChildGenericA : IBaseGenericA<ClassA, ClassB> { }
public class ChildGenericA2<ClassA, ClassB> : BaseGenericA<ClassA, ClassB> { }
public class ChildGenericA3<ClassA, ClassB> : BaseGenericB<ClassA, ClassB, ClassC> { }
public class ChildGenericA4<ClassA, ClassB> : IBaseGenericB<ClassA, ClassB, ClassC> { }
public interface IChildGenericA2<ClassA, ClassB> : IBaseGenericA<ClassA, ClassB> { }
public class WrongBaseGenericA<T, U> { }
public interface IWrongBaseGenericA<T, U> { }
public interface IInterfaceBidonA { }
JaredPar's code works but only for one level of inheritance. For unlimited levels of inheritance, use the following code
public bool IsTypeDerivedFromGenericType(Type typeToCheck, Type genericType)
{
if (typeToCheck == typeof(object))
{
return false;
}
else if (typeToCheck == null)
{
return false;
}
else if (typeToCheck.IsGenericType && typeToCheck.GetGenericTypeDefinition() == genericType)
{
return true;
}
else
{
return IsTypeDerivedFromGenericType(typeToCheck.BaseType, genericType);
}
}
Here's a little method I created for checking that a object is derived from a specific type. Works great for me!
internal static bool IsDerivativeOf(this Type t, Type typeToCompare)
{
if (t == null) throw new NullReferenceException();
if (t.BaseType == null) return false;
if (t.BaseType == typeToCompare) return true;
else return t.BaseType.IsDerivativeOf(typeToCompare);
}
This can all be done easily with linq. This will find any types that are a subclass of generic base class GenericBaseType.
IEnumerable<Type> allTypes = Assembly.GetExecutingAssembly().GetTypes();
IEnumerable<Type> mySubclasses = allTypes.Where(t => t.BaseType != null
&& t.BaseType.IsGenericType
&& t.BaseType.GetGenericTypeDefinition() == typeof(GenericBaseType<,>));
Simple solution: just create and add a second, non-generic interface to the generic class:
public interface IGenericClass
{
}
public class GenericClass<T> : GenericInterface<T>, IGenericClass
{
}
Then just check for that in any way you like using is, as, IsAssignableFrom, etc.
if (thing is IGenericClass)
{
// Do work
{
Obviously only possible if you have the ability to edit the generic class (which the OP seems to have), but it's a bit more elegant and readable than using a cryptic extension method.
Added to #jaredpar's answer, here's what I use to check for interfaces:
public static bool IsImplementerOfRawGeneric(this Type type, Type toCheck)
{
if (toCheck.GetTypeInfo().IsClass)
{
return false;
}
return type.GetInterfaces().Any(interfaceType =>
{
var current = interfaceType.GetTypeInfo().IsGenericType ?
interfaceType.GetGenericTypeDefinition() : interfaceType;
return current == toCheck;
});
}
public static bool IsSubTypeOfRawGeneric(this Type type, Type toCheck)
{
return type.IsInterface ?
IsImplementerOfRawGeneric(type, toCheck)
: IsSubclassOfRawGeneric(type, toCheck);
}
Ex:
Console.WriteLine(typeof(IList<>).IsSubTypeOfRawGeneric(typeof(IList<int>))); // true
Updated Answer
This method checks if typeA equals, inherts (class : class), implements (class : interface) or extends (interface : interface) typeB. It accepts generic and non-generic interfaces and classes.
public static bool Satisfies(Type typeA, Type typeB)
{
var types = new List<Type>(typeA.GetInterfaces());
for (var t = typeA; t != null; t = t.BaseType)
{
types.Add(t);
}
return types.Any(t =>
t == typeB ||
t.IsGenericType && (t.GetGenericTypeDefinition() == typeB));
}
Used in the following it passes 74 of the 76 of the tests #Xav987's answer (It doesn't pass tests '68-3' and '69-3' but I think these tests imply List<Giraffe> is a subclass of List<Animal> and I don't think it is. E.g., List<Giraffe> cannot be cast to a List<Animal>, see https://stackoverflow.com/a/9891849/53252.)
public static bool IsSubClassOfGeneric(this Type typeA, Type typeB)
{
if (typeA == typeB)
{
return false;
}
return Satisfies(typeA, typeB);
}
Examples:
using System.Collections;
using System.Numerics;
void ShowSatisfaction(Type typeA, Type typeB)
{
var satisfied = Satisfies(typeA, typeB);
Console.WriteLine($"{satisfied}: [{typeA}] satisfies [{typeB}]");
}
ShowSatisfaction(typeof(object), typeof(string));
ShowSatisfaction(typeof(string), typeof(object));
ShowSatisfaction(typeof(string), typeof(IEnumerable));
ShowSatisfaction(typeof(string), typeof(IEnumerable<>));
ShowSatisfaction(typeof(string), typeof(IEnumerable<char>));
ShowSatisfaction(typeof(string), typeof(IEnumerable<int>));
ShowSatisfaction(typeof(int), typeof(object));
ShowSatisfaction(typeof(int), typeof(IComparable));
ShowSatisfaction(typeof(IReadOnlyDictionary<,>), typeof(IReadOnlyCollection<>));
ShowSatisfaction(typeof(bool), typeof(INumber<>));
ShowSatisfaction(typeof(int), typeof(INumber<>));
ShowSatisfaction(typeof(IBinaryInteger<>), typeof(IShiftOperators<,>));
ShowSatisfaction(typeof(IBinaryInteger<int>), typeof(IShiftOperators<,>));
ShowSatisfaction(typeof(IBinaryInteger<int>), typeof(IShiftOperators<int, int>));
Output:
False: [System.Object] satisfies [System.String]
True: [System.String] satisfies [System.Object]
True: [System.String] satisfies [System.Collections.IEnumerable]
True: [System.String] satisfies [System.Collections.Generic.IEnumerable`1[T]]
True: [System.String] satisfies [System.Collections.Generic.IEnumerable`1[System.Char]]
False: [System.String] satisfies [System.Collections.Generic.IEnumerable`1[System.Int32]]
True: [System.Int32] satisfies [System.Object]
True: [System.Int32] satisfies [System.IComparable]
True: [System.Collections.Generic.IReadOnlyDictionary`2[TKey,TValue]] satisfies [System.Collections.Generic.IReadOnlyCollection`1[T]]
False: [System.Boolean] satisfies [System.Numerics.INumber`1[TSelf]]
True: [System.Int32] satisfies [System.Numerics.INumber`1[TSelf]]
True: [System.Numerics.IBinaryInteger`1[TSelf]] satisfies [System.Numerics.IShiftOperators`2[TSelf,TResult]]
True: [System.Numerics.IBinaryInteger`1[System.Int32]] satisfies [System.Numerics.IShiftOperators`2[TSelf,TResult]]
True: [System.Numerics.IBinaryInteger`1[System.Int32]] satisfies [System.Numerics.IShiftOperators`2[System.Int32,System.Int32]]
INumber<> examples are from .NET 7 preview 5.
Previous Answer
It might be overkill but I use extension methods like the following. They check interfaces as well as subclasses. It can also return the type that has the specified generic definition.
E.g. for the example in the question it can test against generic interface as well as generic class. The returned type can be used with GetGenericArguments to determine that the generic argument type is "SomeType".
/// <summary>
/// Checks whether this type has the specified definition in its ancestry.
/// </summary>
public static bool HasGenericDefinition(this Type type, Type definition)
{
return GetTypeWithGenericDefinition(type, definition) != null;
}
/// <summary>
/// Returns the actual type implementing the specified definition from the
/// ancestry of the type, if available. Else, null.
/// </summary>
public static Type GetTypeWithGenericDefinition(this Type type, Type definition)
{
if (type == null)
throw new ArgumentNullException("type");
if (definition == null)
throw new ArgumentNullException("definition");
if (!definition.IsGenericTypeDefinition)
throw new ArgumentException(
"The definition needs to be a GenericTypeDefinition", "definition");
if (definition.IsInterface)
foreach (var interfaceType in type.GetInterfaces())
if (interfaceType.IsGenericType
&& interfaceType.GetGenericTypeDefinition() == definition)
return interfaceType;
for (Type t = type; t != null; t = t.BaseType)
if (t.IsGenericType && t.GetGenericTypeDefinition() == definition)
return t;
return null;
}
Building on the excellent answer above by fir3rpho3nixx and David Schmitt, I have modified their code and added the ShouldInheritOrImplementTypedGenericInterface test (last one).
/// <summary>
/// Find out if a child type implements or inherits from the parent type.
/// The parent type can be an interface or a concrete class, generic or non-generic.
/// </summary>
/// <param name="child"></param>
/// <param name="parent"></param>
/// <returns></returns>
public static bool InheritsOrImplements(this Type child, Type parent)
{
var currentChild = parent.IsGenericTypeDefinition && child.IsGenericType ? child.GetGenericTypeDefinition() : child;
while (currentChild != typeof(object))
{
if (parent == currentChild || HasAnyInterfaces(parent, currentChild))
return true;
currentChild = currentChild.BaseType != null && parent.IsGenericTypeDefinition && currentChild.BaseType.IsGenericType
? currentChild.BaseType.GetGenericTypeDefinition()
: currentChild.BaseType;
if (currentChild == null)
return false;
}
return false;
}
private static bool HasAnyInterfaces(Type parent, Type child)
{
return child.GetInterfaces().Any(childInterface =>
{
var currentInterface = parent.IsGenericTypeDefinition && childInterface.IsGenericType
? childInterface.GetGenericTypeDefinition()
: childInterface;
return currentInterface == parent;
});
}
[Test]
public void ShouldInheritOrImplementNonGenericInterface()
{
Assert.That(typeof(FooImplementor)
.InheritsOrImplements(typeof(IFooInterface)), Is.True);
}
[Test]
public void ShouldInheritOrImplementGenericInterface()
{
Assert.That(typeof(GenericFooBase)
.InheritsOrImplements(typeof(IGenericFooInterface<>)), Is.True);
}
[Test]
public void ShouldInheritOrImplementGenericInterfaceByGenericSubclass()
{
Assert.That(typeof(GenericFooImplementor<>)
.InheritsOrImplements(typeof(IGenericFooInterface<>)), Is.True);
}
[Test]
public void ShouldInheritOrImplementGenericInterfaceByGenericSubclassNotCaringAboutGenericTypeParameter()
{
Assert.That(new GenericFooImplementor<string>().GetType()
.InheritsOrImplements(typeof(IGenericFooInterface<>)), Is.True);
}
[Test]
public void ShouldNotInheritOrImplementGenericInterfaceByGenericSubclassNotCaringAboutGenericTypeParameter()
{
Assert.That(new GenericFooImplementor<string>().GetType()
.InheritsOrImplements(typeof(IGenericFooInterface<int>)), Is.False);
}
[Test]
public void ShouldInheritOrImplementNonGenericClass()
{
Assert.That(typeof(FooImplementor)
.InheritsOrImplements(typeof(FooBase)), Is.True);
}
[Test]
public void ShouldInheritOrImplementAnyBaseType()
{
Assert.That(typeof(GenericFooImplementor<>)
.InheritsOrImplements(typeof(FooBase)), Is.True);
}
[Test]
public void ShouldInheritOrImplementTypedGenericInterface()
{
GenericFooImplementor<int> obj = new GenericFooImplementor<int>();
Type t = obj.GetType();
Assert.IsTrue(t.InheritsOrImplements(typeof(IGenericFooInterface<int>)));
Assert.IsFalse(t.InheritsOrImplements(typeof(IGenericFooInterface<String>)));
}
JaredPar,
This did not work for me if I pass typeof(type<>) as toCheck. Here's what I changed.
static bool IsSubclassOfRawGeneric(Type generic, Type toCheck) {
while (toCheck != typeof(object)) {
var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
if (cur.IsGenericType && generic.GetGenericTypeDefinition() == cur.GetGenericTypeDefinition()) {
return true;
}
toCheck = toCheck.BaseType;
}
return false;
}
#EnocNRoll - Ananda Gopal 's answer is interesting, but in case an instance is not instantiated beforehand or you want to check with a generic type definition, I'd suggest this method:
public static bool TypeIs(this Type x, Type d) {
if(null==d) {
return false;
}
for(var c = x; null!=c; c=c.BaseType) {
var a = c.GetInterfaces();
for(var i = a.Length; i-->=0;) {
var t = i<0 ? c : a[i];
if(t==d||t.IsGenericType&&t.GetGenericTypeDefinition()==d) {
return true;
}
}
}
return false;
}
and use it like:
var b = typeof(char[]).TypeIs(typeof(IList<>)); // true
There are four conditional cases when both t(to be tested) and d are generic types and two cases are covered by t==d which are (1)neither t nor d is a generic definition or (2) both of them are generic definitions. The rest cases are one of them is a generic definition, only when d is already a generic definition we have the chance to say a t is a d but not vice versa.
It should work with arbitrary classes or interfaces you want to test, and returns what as if you test an instance of that type with the is operator.
Type _type = myclass.GetType();
PropertyInfo[] _propertyInfos = _type.GetProperties();
Boolean _test = _propertyInfos[0].PropertyType.GetGenericTypeDefinition()
== typeof(List<>);
You can try this extension
public static bool IsSubClassOfGenericClass(this Type type, Type genericClass,Type t)
{
return type.IsSubclassOf(genericClass.MakeGenericType(new[] { t }));
}
late to the game on this... i too have yet another permutation of JarodPar's answer.
here's Type.IsSubClassOf(Type) courtesy of reflector:
public virtual bool IsSubclassOf(Type c)
{
Type baseType = this;
if (!(baseType == c))
{
while (baseType != null)
{
if (baseType == c)
{
return true;
}
baseType = baseType.BaseType;
}
return false;
}
return false;
}
from that, we see that it's not doing anything too cray cray and is similar to JaredPar's iterative approach. so far, so good. here's my version (disclaimer: not thoroughly tested, so lemme know if you find issues)
public static bool IsExtension(this Type thisType, Type potentialSuperType)
{
//
// protect ya neck
//
if (thisType == null || potentialSuperType == null || thisType == potentialSuperType) return false;
//
// don't need to traverse inheritance for interface extension, so check/do these first
//
if (potentialSuperType.IsInterface)
{
foreach (var interfaceType in thisType.GetInterfaces())
{
var tempType = interfaceType.IsGenericType ? interfaceType.GetGenericTypeDefinition() : interfaceType;
if (tempType == potentialSuperType)
{
return true;
}
}
}
//
// do the concrete type checks, iterating up the inheritance chain, as in orignal
//
while (thisType != null && thisType != typeof(object))
{
var cur = thisType.IsGenericType ? thisType.GetGenericTypeDefinition() : thisType;
if (potentialSuperType == cur)
{
return true;
}
thisType = thisType.BaseType;
}
return false;
}
basically this is just an extension method to System.Type - i did this to intentionally limit the "thisType" Type to concrete Types, as my immediate usage is to LINQ query "where" predicates against Type objects. i'm sure all you smart folks out there could bang it down to an efficient, all-purpose static method if you need to :) the code does a few things the answer's code doesn't
open's it up to to general "extension" - i'm considering inheritance (think classes)
as well as implementation (interfaces); method and parameter names
are changed to better reflect this
input null-validation (meah)
input of same type (a class cannot extend itself)
short-circuit execution if Type in question is an interface; because GetInterfaces() returns all implemented interfaces (even ones implemented in super-classes), you can simply loop through that collection not having to climb the inheritance tree
the rest is basically the same as JaredPar's code

How to determine if a type implements a specific generic interface type

Assume the following type definitions:
public interface IFoo<T> : IBar<T> {}
public class Foo<T> : IFoo<T> {}
How do I find out whether the type Foo implements the generic interface IBar<T> when only the mangled type is available?
By using the answer from TcKs it can also be done with the following LINQ query:
bool isBar = foo.GetType().GetInterfaces().Any(x =>
x.IsGenericType &&
x.GetGenericTypeDefinition() == typeof(IBar<>));
You have to go up through the inheritance tree and find all the interfaces for each class in the tree, and compare typeof(IBar<>) with the result of calling Type.GetGenericTypeDefinition if the interface is generic. It's all a bit painful, certainly.
See this answer and these ones for more info and code.
public interface IFoo<T> : IBar<T> {}
public class Foo : IFoo<Foo> {}
var implementedInterfaces = typeof( Foo ).GetInterfaces();
foreach( var interfaceType in implementedInterfaces ) {
if ( false == interfaceType.IsGeneric ) { continue; }
var genericType = interfaceType.GetGenericTypeDefinition();
if ( genericType == typeof( IFoo<> ) ) {
// do something !
break;
}
}
As a helper method extension
public static bool Implements<I>(this Type type, I #interface) where I : class
{
if(((#interface as Type)==null) || !(#interface as Type).IsInterface)
throw new ArgumentException("Only interfaces can be 'implemented'.");
return (#interface as Type).IsAssignableFrom(type);
}
Example usage:
var testObject = new Dictionary<int, object>();
result = testObject.GetType().Implements(typeof(IDictionary<int, object>)); // true!
I'm using a slightly simpler version of #GenericProgrammers extension method:
public static bool Implements<TInterface>(this Type type) where TInterface : class {
var interfaceType = typeof(TInterface);
if (!interfaceType.IsInterface)
throw new InvalidOperationException("Only interfaces can be implemented.");
return (interfaceType.IsAssignableFrom(type));
}
Usage:
if (!featureType.Implements<IFeature>())
throw new InvalidCastException();
To tackle the type system completely, I think you need to handle recursion, e.g. IList<T> : ICollection<T> : IEnumerable<T>, without which you wouldn't know that IList<int> ultimately implements IEnumerable<>.
/// <summary>Determines whether a type, like IList<int>, implements an open generic interface, like
/// IEnumerable<>. Note that this only checks against *interfaces*.</summary>
/// <param name="candidateType">The type to check.</param>
/// <param name="openGenericInterfaceType">The open generic type which it may impelement</param>
/// <returns>Whether the candidate type implements the open interface.</returns>
public static bool ImplementsOpenGenericInterface(this Type candidateType, Type openGenericInterfaceType)
{
Contract.Requires(candidateType != null);
Contract.Requires(openGenericInterfaceType != null);
return
candidateType.Equals(openGenericInterfaceType) ||
(candidateType.IsGenericType && candidateType.GetGenericTypeDefinition().Equals(openGenericInterfaceType)) ||
candidateType.GetInterfaces().Any(i => i.IsGenericType && i.ImplementsOpenGenericInterface(openGenericInterfaceType));
}
In case you wanted an extension method that would support generic base types as well as interfaces, I've expanded sduplooy's answer:
public static bool InheritsFrom(this Type t1, Type t2)
{
if (null == t1 || null == t2)
return false;
if (null != t1.BaseType &&
t1.BaseType.IsGenericType &&
t1.BaseType.GetGenericTypeDefinition() == t2)
{
return true;
}
if (InheritsFrom(t1.BaseType, t2))
return true;
return
(t2.IsAssignableFrom(t1) && t1 != t2)
||
t1.GetInterfaces().Any(x =>
x.IsGenericType &&
x.GetGenericTypeDefinition() == t2);
}
You have to check against a constructed type of the generic interface.
You will have to do something like this:
foo is IBar<String>
because IBar<String> represents that constructed type. The reason you have to do this is because if T is undefined in your check, the compiler doesn't know if you mean IBar<Int32> or IBar<SomethingElse>.
First of all public class Foo : IFoo<T> {} does not compile because you need to specify a class instead of T, but assuming you do something like public class Foo : IFoo<SomeClass> {}
then if you do
Foo f = new Foo();
IBar<SomeClass> b = f as IBar<SomeClass>;
if(b != null) //derives from IBar<>
Blabla();
Method to check if the type inherits or implements a generic type:
public static bool IsTheGenericType(this Type candidateType, Type genericType)
{
return
candidateType != null && genericType != null &&
(candidateType.IsGenericType && candidateType.GetGenericTypeDefinition() == genericType ||
candidateType.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == genericType) ||
candidateType.BaseType != null && candidateType.BaseType.IsTheGenericType(genericType));
}
Try the following extension.
public static bool Implements(this Type #this, Type #interface)
{
if (#this == null || #interface == null) return false;
return #interface.GenericTypeArguments.Length>0
? #interface.IsAssignableFrom(#this)
: #this.GetInterfaces().Any(c => c.Name == #interface.Name);
}
To test it. create
public interface IFoo { }
public interface IFoo<T> : IFoo { }
public interface IFoo<T, M> : IFoo<T> { }
public class Foo : IFoo { }
public class Foo<T> : IFoo { }
public class Foo<T, M> : IFoo<T> { }
public class FooInt : IFoo<int> { }
public class FooStringInt : IFoo<string, int> { }
public class Foo2 : Foo { }
and the test method
public void Test()
{
Console.WriteLine(typeof(Foo).Implements(typeof(IFoo)));
Console.WriteLine(typeof(FooInt).Implements(typeof(IFoo)));
Console.WriteLine(typeof(FooInt).Implements(typeof(IFoo<>)));
Console.WriteLine(typeof(FooInt).Implements(typeof(IFoo<int>)));
Console.WriteLine(typeof(FooInt).Implements(typeof(IFoo<string>)));
Console.WriteLine(typeof(FooInt).Implements(typeof(IFoo<,>)));
Console.WriteLine(typeof(FooStringInt).Implements(typeof(IFoo<,>)));
Console.WriteLine(typeof(FooStringInt).Implements(typeof(IFoo<string,int>)));
Console.WriteLine(typeof(Foo<int,string>).Implements(typeof(IFoo<string>)));
}
var genericType = typeof(ITest<>);
Console.WriteLine(typeof(Test).GetInterfaces().Any(x => x.GetGenericTypeDefinition().Equals(genericType))); // prints: "True"
interface ITest<T> { };
class Test : ITest<string> { }
This worked for me.
You can add the below extension method:
public static TypeExtension
{
public static bool IsImplement<T>(this Type type)
{
return type.IsImplement(typeof(T));
}
public static bool IsImplement(this Type type, Type interfaceType)
{
if (!interfaceType.IsInterface)
throw new InvalidOperationException("Only interfaces can be implemented.");
return type.IsAssignableTo(interfaceType) ||
interfaceType.IsGenericType && type.GetInterfaces()
.Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == interfaceType.GetGenericTypeDefinition());
}
}
There shouldn't be anything wrong the following:
bool implementsGeneric = (anObject.Implements("IBar`1") != null);
For extra credit you could catch AmbiguousMatchException if you wanted to provide a specific generic-type-parameter with your IBar query.

Categories

Resources