开发者

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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜