Anne
Anne

Reputation: 105

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 solve fix this problem?

Upvotes: 1

Views: 1975

Answers (4)

gregsdennis
gregsdennis

Reputation: 8428

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

Upvotes: 0

SLaks
SLaks

Reputation: 888077

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.

Upvotes: 1

HABJAN
HABJAN

Reputation: 9338

Change your method with this and it will work:

private static bool OpenGenericTypeImplementsOpenGenericInterface(
    Type derivedType, Type interfaceType)
{
    return derivedType.GetInterface(interfaceType.Name) != null;
}

Upvotes: 1

jason
jason

Reputation: 241769

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

Upvotes: 3

Related Questions