How to check if a generic type definition inherits from another generic type definition
I'm trying to check whether an open generic type definition implements some open generic interface. Look at the sample below:
public interface IService<T> { }
public class ServiceImpl<T> : IService<T> { }
private static bool OpenGenericTypeImplementsOpenGenericInterface(
Type derivedType, Type interfaceType)
{
return derivedType.GetInterfaces().Contains(interfaceType);
}
[TestMethod]
public void Verify()
{
Type openGenericImplementation = typeof(ServiceImpl<>);
Type expectedInterfaceType = typeof(IService<>);
bool implDoesImplementInterface = OpenGenericTypeImplementsOpenGenericInterface(
openGenericImplementation, expectedInterfaceType);
// This assert fails. Why?
Assert.IsTrue(implDoesImplementInterface);
}
I found out that the returned type from the Type.GetInterfaces()
method does not match the type returned from typeof(IService<>)
. I can't figure out why that is and how to correctly validate whether some generic type definition inherits or implements some other generic type definition.
What's going on here and how do I solv开发者_运维知识库e fix this problem?
The problem is that GetInterfaces
returns closed types so you need to open them using GetGenericTypeDefinition
:
public static bool ImplementsOpenInterface(Type type, Type openInterfaceType) {
Contract.Requires(type != null);
Contract.Requires(openInterfaceType != null);
Contract.Requires(openInterfaceType.IsGenericTypeDefinition);
Type[] interfaces = type.GetInterfaces();
if (interfaces == null) {
return false;
}
return interfaces
.Where(x => x.IsGenericType)
.Select(x => x.GetGenericTypeDefinition())
.Any(x => x == openInterfaceType);
}
Change your method with this and it will work:
private static bool OpenGenericTypeImplementsOpenGenericInterface(
Type derivedType, Type interfaceType)
{
return derivedType.GetInterface(interfaceType.Name) != null;
}
GetInterfaces()
will return a closed Type object with the generic parameter that it implements the interface with.
Instead, use LINQ:
return derivedType.GetInterfaces().Any(i =>
i == interfaceType
|| (i.ContainsGenericParameters && i.GetGenericTypeDefinition() == interfaceType))
This code checks whether any of the interfaces that it implements is a parameterized version of your interface.
I had a need to expand on this to include type inheritance in addition to interfaces. Here's what I came up with:
interface IFace<T> {}
class Impl<T> : IFace<T> {}
class Derived<T> : Impl<T> {}
public static bool InheritsFrom(this Type tDerived, Type tBase)
{
if (tDerived.IsSubtypeOf(tBase)) return true;
var interfaces = tDerived.GetInterfaces()
.Select(i => i.IsGenericType ? i.GetGenericTypeDefinition() : i);
return interfaces.Contains(tBase);
}
public static bool IsSubtypeOf(this Type tDerived, Type tBase)
{
var currentType = tDerived.BaseType;
while (currentType != null)
{
if (currentType.IsGenericType)
currentType = currentType.GetGenericTypeDefinition();
if (currentType == tBase) return true;
currentType = currentType.BaseType;
}
return false;
}
Note that while these methods will work on any two types, they assume that if a generic type is passed, the type is open (that is, it is the generic type definition without defined type parameters).
精彩评论