如何检查泛型类型定义是否继承自另一个泛型类型定义

时间:2022-09-25 12:11:09

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.

我发现Type.GetInterfaces()方法返回的类型与typeof(IService <>)返回的类型不匹配。我无法弄清楚为什么会这样,以及如何正确验证某些泛型类型定义是继承还是实现其他泛型类型定义。

What's going on here and how do I solve fix this problem?

这里发生了什么,我该如何解决这个问题呢?

4 个解决方案

#1


3  

The problem is that GetInterfaces returns closed types so you need to open them using GetGenericTypeDefinition:

问题是GetInterfaces返回闭合类型,因此您需要使用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);
}

#2


1  

Change your method with this and it will work:

用这个改变你的方法,它将工作:

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

#3


1  

GetInterfaces() will return a closed Type object with the generic parameter that it implements the interface with.

GetInterfaces()将返回一个封闭的Type对象,其中包含与其实现接口的泛型参数。

Instead, use LINQ:

相反,使用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.

此代码检查它实现的任何接口是否是接口的参数化版本。

#4


0  

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

请注意,虽然这些方法适用于任何两种类型,但它们假定如果传递泛型类型,则类型是开放的(即,它是没有定义类型参数的泛型类型定义)。

#1


3  

The problem is that GetInterfaces returns closed types so you need to open them using GetGenericTypeDefinition:

问题是GetInterfaces返回闭合类型,因此您需要使用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);
}

#2


1  

Change your method with this and it will work:

用这个改变你的方法,它将工作:

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

#3


1  

GetInterfaces() will return a closed Type object with the generic parameter that it implements the interface with.

GetInterfaces()将返回一个封闭的Type对象,其中包含与其实现接口的泛型参数。

Instead, use LINQ:

相反,使用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.

此代码检查它实现的任何接口是否是接口的参数化版本。

#4


0  

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

请注意,虽然这些方法适用于任何两种类型,但它们假定如果传递泛型类型,则类型是开放的(即,它是没有定义类型参数的泛型类型定义)。