我有一个泛型类在我的项目与派生类。
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<>))
不管用。
当前回答
这个游戏已经晚了…我对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的答案中,下面是我用来检查接口的方法:
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
我研究了其中一些样本,发现它们在某些情况下是缺乏的。这个版本适用于所有类型的泛型:类型、接口及其类型定义。
public static bool InheritsOrImplements(this Type child, Type parent)
{
parent = ResolveGenericTypeDefinition(parent);
var currentChild = child.IsGenericType
? child.GetGenericTypeDefinition()
: child;
while (currentChild != typeof (object))
{
if (parent == currentChild || HasAnyInterfaces(parent, currentChild))
return true;
currentChild = currentChild.BaseType != null
&& currentChild.BaseType.IsGenericType
? currentChild.BaseType.GetGenericTypeDefinition()
: currentChild.BaseType;
if (currentChild == null)
return false;
}
return false;
}
private static bool HasAnyInterfaces(Type parent, Type child)
{
return child.GetInterfaces()
.Any(childInterface =>
{
var currentInterface = childInterface.IsGenericType
? childInterface.GetGenericTypeDefinition()
: childInterface;
return currentInterface == parent;
});
}
private static Type ResolveGenericTypeDefinition(Type parent)
{
var shouldUseGenericType = true;
if (parent.IsGenericType && parent.GetGenericTypeDefinition() != parent)
shouldUseGenericType = false;
if (parent.IsGenericType && shouldUseGenericType)
parent = parent.GetGenericTypeDefinition();
return parent;
}
下面是单元测试:
protected interface IFooInterface
{
}
protected interface IGenericFooInterface<T>
{
}
protected class FooBase
{
}
protected class FooImplementor
: FooBase, IFooInterface
{
}
protected class GenericFooBase
: FooImplementor, IGenericFooInterface<object>
{
}
protected class GenericFooImplementor<T>
: FooImplementor, IGenericFooInterface<T>
{
}
[Test]
public void Should_inherit_or_implement_non_generic_interface()
{
Assert.That(typeof(FooImplementor)
.InheritsOrImplements(typeof(IFooInterface)), Is.True);
}
[Test]
public void Should_inherit_or_implement_generic_interface()
{
Assert.That(typeof(GenericFooBase)
.InheritsOrImplements(typeof(IGenericFooInterface<>)), Is.True);
}
[Test]
public void Should_inherit_or_implement_generic_interface_by_generic_subclass()
{
Assert.That(typeof(GenericFooImplementor<>)
.InheritsOrImplements(typeof(IGenericFooInterface<>)), Is.True);
}
[Test]
public void Should_inherit_or_implement_generic_interface_by_generic_subclass_not_caring_about_generic_type_parameter()
{
Assert.That(new GenericFooImplementor<string>().GetType()
.InheritsOrImplements(typeof(IGenericFooInterface<>)), Is.True);
}
[Test]
public void Should_not_inherit_or_implement_generic_interface_by_generic_subclass_not_caring_about_generic_type_parameter()
{
Assert.That(new GenericFooImplementor<string>().GetType()
.InheritsOrImplements(typeof(IGenericFooInterface<int>)), Is.False);
}
[Test]
public void Should_inherit_or_implement_non_generic_class()
{
Assert.That(typeof(FooImplementor)
.InheritsOrImplements(typeof(FooBase)), Is.True);
}
[Test]
public void Should_inherit_or_implement_any_base_type()
{
Assert.That(typeof(GenericFooImplementor<>)
.InheritsOrImplements(typeof(FooBase)), Is.True);
}
更新后的答案
这个方法检查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;
}
这些都可以用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<,>));
@EnocNRoll - Ananda Gopal的回答很有趣,但如果一个实例没有预先实例化,或者你想用泛型类型定义检查,我建议使用这个方法:
public static bool TypeIs(this Type x, Type d) {
if(null==d) {
return false;
}
for(var c = x; null!=c; c=c.BaseType) {
var a = c.GetInterfaces();
for(var i = a.Length; i-->=0;) {
var t = i<0 ? c : a[i];
if(t==d||t.IsGenericType&&t.GetGenericTypeDefinition()==d) {
return true;
}
}
}
return false;
}
像这样使用它:
var b = typeof(char[]).TypeIs(typeof(IList<>)); // true
有四种条件情况,t(待测)和d都是泛型类型,t==d涵盖了两种情况,即(1)t和d都不是泛型定义或(2)它们都是泛型定义。其余的情况是其中一个是一般定义,只有当d已经是一般定义时我们才有机会说t是d,而不是反过来。
它应该与您想要测试的任意类或接口一起工作,并返回与使用is操作符测试该类型的实例一样的结果。