我有一个泛型类在我的项目与派生类。
public class GenericClass<T> : GenericInterface<T>
{
}
public class Test : GenericClass<SomeType>
{
}
是否有任何方法可以查明Type对象是否派生自GenericClass?
t.IsSubclassOf(typeof(GenericClass<>))
不管用。
我有一个泛型类在我的项目与派生类。
public class GenericClass<T> : GenericInterface<T>
{
}
public class Test : GenericClass<SomeType>
{
}
是否有任何方法可以查明Type对象是否派生自GenericClass?
t.IsSubclassOf(typeof(GenericClass<>))
不管用。
当前回答
添加到@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
其他回答
下面是我创建的一个小方法,用于检查对象是否派生于特定类型。对我来说太棒了!
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);
}
简单的解决方案:只需创建并添加第二个非泛型接口到泛型类:
public interface IGenericClass
{
}
public class GenericClass<T> : GenericInterface<T>, IGenericClass
{
}
然后用is as IsAssignableFrom等任何你喜欢的方式检查。
if (thing is IGenericClass)
{
// Do work
{
显然,只有当您能够编辑泛型类(OP似乎具有这种能力)时才有可能,但它比使用神秘的扩展方法更优雅、更可读。
这个游戏已经晚了…我对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的代码相同
(由于大量重写而重新发布)
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);
添加到@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