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

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

public class Test : GenericClass<SomeType>
{
}

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

t.IsSubclassOf(typeof(GenericClass<>))

不管用。


当前回答

下面是我创建的一个小方法,用于检查对象是否派生于特定类型。对我来说太棒了!

internal static bool IsDerivativeOf(this Type t, Type typeToCompare)
{
    if (t == null) throw new NullReferenceException();
    if (t.BaseType == null) return false;

    if (t.BaseType == typeToCompare) return true;
    else return t.BaseType.IsDerivativeOf(typeToCompare);
}

其他回答

(由于大量重写而重新发布)

JaredPar的代码回答非常棒,但是我有一个技巧,如果您的泛型类型不是基于值类型参数,那么就没有必要这样做。我一直纠结于为什么“is”操作符不能工作,所以我还记录了我的实验结果,以供将来参考。请加强这个答案,以进一步提高其清晰度。

TIP:

如果你确定你的GenericClass实现继承自一个抽象的非泛型基类,比如GenericClassBase,你可以毫不费力地问同样的问题,就像这样:

typeof(Test).IsSubclassOf(typeof(GenericClassBase))

IsSubclassOf()

我的测试表明IsSubclassOf()不适用于无参数的泛型类型,例如

typeof(GenericClass<>)

而它将与

typeof(GenericClass<SomeType>)

因此,以下代码将适用于GenericClass<>的任何派生,假设您愿意基于SomeType进行测试:

typeof(Test).IsSubclassOf(typeof(GenericClass<SomeType>))

我能想象到您希望通过GenericClass<>进行测试的唯一情况是在插件框架场景中。


对“is”操作符的思考

在设计时,c#不允许使用无参数泛型,因为那时它们本质上还不是一个完整的CLR类型。因此,必须声明带参数的泛型变量,这就是“is”操作符在处理对象时如此强大的原因。顺便说一句,“is”操作符也不能计算无参数的泛型类型。

“is”操作符将测试整个继承链,包括接口。

因此,给定任何对象的实例,下面的方法就可以做到:

bool IsTypeof<T>(object t)
{
    return (t is T);
}

这有点多余,但我想我可以把它可视化给大家。

鉴于

var t = new Test();

下面几行代码将返回true:

bool test1 = IsTypeof<GenericInterface<SomeType>>(t);

bool test2 = IsTypeof<GenericClass<SomeType>>(t);

bool test3 = IsTypeof<Test>(t);

另一方面,如果你想要一些特定于GenericClass的东西,你可以让它更具体,我想,像这样:

bool IsTypeofGenericClass<SomeType>(object t)
{
    return (t is GenericClass<SomeType>);
}

然后你可以这样测试:

bool test1 = IsTypeofGenericClass<SomeType>(t);

简单的解决方案:只需创建并添加第二个非泛型接口到泛型类:

public interface IGenericClass
{
}

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

然后用is as IsAssignableFrom等任何你喜欢的方式检查。

if (thing is IGenericClass)
{
    // Do work
{

显然,只有当您能够编辑泛型类(OP似乎具有这种能力)时才有可能,但它比使用神秘的扩展方法更优雅、更可读。

添加到@jaredpar的答案中,下面是我用来检查接口的方法:

public static bool IsImplementerOfRawGeneric(this Type type, Type toCheck)
{
    if (toCheck.GetTypeInfo().IsClass)
    {
        return false;
    }

    return type.GetInterfaces().Any(interfaceType =>
    {
        var current = interfaceType.GetTypeInfo().IsGenericType ?
                    interfaceType.GetGenericTypeDefinition() : interfaceType;
        return current == toCheck;
    });
}

public static bool IsSubTypeOfRawGeneric(this Type type, Type toCheck)
{
    return type.IsInterface ?
          IsImplementerOfRawGeneric(type, toCheck)
        : IsSubclassOfRawGeneric(type, toCheck);
}

Ex:

Console.WriteLine(typeof(IList<>).IsSubTypeOfRawGeneric(typeof(IList<int>))); // true

JaredPar的代码可以工作,但只适用于一个继承级别。要获得无限级别的继承,请使用以下代码

public bool IsTypeDerivedFromGenericType(Type typeToCheck, Type genericType)
{
    if (typeToCheck == typeof(object))
    {
        return false;
    }
    else if (typeToCheck == null)
    {
        return false;
    }
    else if (typeToCheck.IsGenericType && typeToCheck.GetGenericTypeDefinition() == genericType)
    {
        return true;
    }
    else
    {
        return IsTypeDerivedFromGenericType(typeToCheck.BaseType, genericType);
    }
}

这些都可以用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<,>));