我有一个泛型类在我的项目与派生类。

public class GenericClass<T> : GenericInterface<T>
{
}

public class Test : GenericClass<SomeType>
{
}

是否有任何方法可以查明Type对象是否派生自GenericClass?

t.IsSubclassOf(typeof(GenericClass<>))

不管用。


当前回答

更新后的答案

这个方法检查typeA是否等于、继承(class: class)、实现(class: interface)或扩展(interface: interface) typeB。它接受泛型和非泛型接口和类。

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

在下面使用,它通过了76个测试中的74个@Xav987的答案(它没有通过测试'68-3'和'69-3',但我认为这些测试暗示List<长颈鹿>是List<动物>的子类,我不认为它是。例如,List<长颈鹿>不能施放到List<动物>,参见https://stackoverflow.com/a/9891849/53252。)

public static bool IsSubClassOfGeneric(this Type typeA, Type typeB)
{
    if (typeA == typeB)
    {
        return false;
    }
    return Satisfies(typeA, typeB);
}

例子:

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

输出:

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<>的例子来自。net 7预览5。

以前的回答

它可能是多余的,但我使用如下扩展方法。它们检查接口和子类。它还可以返回具有指定泛型定义的类型。

例如,对于问题中的例子,它可以测试泛型接口以及泛型类。返回的类型可以与GetGenericArguments一起使用,以确定泛型参数类型是“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;
}

其他回答

试试这段代码

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

这些都可以用linq轻松完成。这将找到泛型基类GenericBaseType的子类的任何类型。

    IEnumerable<Type> allTypes = Assembly.GetExecutingAssembly().GetTypes();

    IEnumerable<Type> mySubclasses = allTypes.Where(t => t.BaseType != null 
                                                            && t.BaseType.IsGenericType
                                                            && t.BaseType.GetGenericTypeDefinition() == typeof(GenericBaseType<,>));

更新后的答案

这个方法检查typeA是否等于、继承(class: class)、实现(class: interface)或扩展(interface: interface) typeB。它接受泛型和非泛型接口和类。

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

在下面使用,它通过了76个测试中的74个@Xav987的答案(它没有通过测试'68-3'和'69-3',但我认为这些测试暗示List<长颈鹿>是List<动物>的子类,我不认为它是。例如,List<长颈鹿>不能施放到List<动物>,参见https://stackoverflow.com/a/9891849/53252。)

public static bool IsSubClassOfGeneric(this Type typeA, Type typeB)
{
    if (typeA == typeB)
    {
        return false;
    }
    return Satisfies(typeA, typeB);
}

例子:

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

输出:

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<>的例子来自。net 7预览5。

以前的回答

它可能是多余的,但我使用如下扩展方法。它们检查接口和子类。它还可以返回具有指定泛型定义的类型。

例如,对于问题中的例子,它可以测试泛型接口以及泛型类。返回的类型可以与GetGenericArguments一起使用,以确定泛型参数类型是“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;
}
Type _type = myclass.GetType();
PropertyInfo[] _propertyInfos = _type.GetProperties();
Boolean _test = _propertyInfos[0].PropertyType.GetGenericTypeDefinition() 
== typeof(List<>);

这个游戏已经晚了…我对JarodPar的答案也有另一种排列。

下面是Type. issubclassof (Type),由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;
    }

由此,我们看到它并没有做任何过于疯狂的事情,并且类似于JaredPar的迭代方法。到目前为止,一切顺利。这是我的版本(免责声明:没有彻底测试,所以如果你发现问题,请告诉我)

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

基本上这只是System的一个扩展方法。类型-我这样做是为了故意将“thisType”类型限制为具体类型,因为我的直接用法是对类型对象的LINQ查询“where”谓词。我相信所有聪明的人都可以把它归结为一个有效的,通用的静态方法,如果你需要:)代码做了一些事情,答案的代码没有

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

其余部分基本上与JaredPar的代码相同