使用IsAssignableFrom和'open'genericstypes
使用reflection,我试图find从给定的基类inheritance的types的集合。 找出简单的types并不需要太长的时间,但是当涉及到非专利types的时候,我却难以理解了。
对于这段代码,第一个IsAssignableFrom返回true,但是第二个返回false。 然而,最后的任务编译得很好。
class class1 { } class class2 : class1 { } class generic1<T> { } class generic2<T> : generic1<T> { } class Program { static void Main(string[] args) { Type c1 = typeof(class1); Type c2 = typeof(class2); Console.WriteLine("c1.IsAssignableFrom(c2): {0}", c1.IsAssignableFrom(c2)); Type g1 = typeof(generic1<>); Type g2 = typeof(generic2<>); Console.WriteLine("g1.IsAssignableFrom(g2): {0}", g1.IsAssignableFrom(g2)); generic1<class1> cc = new generic2<class1>(); } }
那么如何在运行时确定一个genericstypes定义是否从另一个generics定义派生?
从答案到另一个问题 :
public static bool IsAssignableToGenericType(Type givenType, Type genericType) { var interfaceTypes = givenType.GetInterfaces(); foreach (var it in interfaceTypes) { if (it.IsGenericType && it.GetGenericTypeDefinition() == genericType) return true; } if (givenType.IsGenericType && givenType.GetGenericTypeDefinition() == genericType) return true; Type baseType = givenType.BaseType; if (baseType == null) return false; return IsAssignableToGenericType(baseType, genericType); }
(如果你喜欢答案,请upvote链接的答案,因为代码不是我的。)
您发布的确切代码不会返回令人惊讶的结果。
这说“错误”:
Type g1 = typeof(generic1<>); Type g2 = typeof(generic2<>); Console.WriteLine("g1.IsAssignableFrom(g2): {0}", g1.IsAssignableFrom(g2));
这说“真”:
Type g1 = typeof(generic1<class1>); Type g2 = typeof(generic2<class1>); Console.WriteLine("g1.IsAssignableFrom(g2): {0}", g1.IsAssignableFrom(g2));
不同的是,开放的genericstypes不能有实例,所以一个不能“赋值”到另一个。
从文档 :
如果
c
和当前的Type
代表相同的types,或者当前的Type
位于c
的inheritance层次结构中,或者当前的Type
是c
实现的接口,或者c
是genericstypes参数,并且当前的Type
代表c
的约束之一。 如果这些条件都不成立,或者c
为null
,则返回null
。
在这种情况下,显然这些条件都不是真的。 还有一个额外的说明:
genericstypes定义不能从封闭的构造types分配。 也就是说,您不能将封闭的构造types
MyGenericList<int>
(Visual Basic中的MyGenericList(Of Integer)
)分配给MyGenericList<T>
types的variables。
在下面的情况下,使用Konrad Rudolph提供的方法可能是错误的,如:IsAssignableToGenericType(typeof(A),typeof(A <>)); //返回false
我想这是一个更好的答案
public static bool IsAssignableFrom(Type extendType, Type baseType) { while (!baseType.IsAssignableFrom(extendType)) { if (extendType.Equals(typeof(object))) { return false; } if (extendType.IsGenericType && !extendType.IsGenericTypeDefinition) { extendType = extendType.GetGenericTypeDefinition(); } else { extendType = extendType.BaseType; } } return true; }
testing用例,请参阅使用C#generics的IsAssignableFrom来获取详细信息
using System; /** * Sam Sha - yCoder.com * * */ namespace Test2 { class MainClass { public static void Main (string[] args) { string a = "ycoder"; Console.WriteLine(a is object); A aa = new A(); //Console.WriteLine(aa is A<>);//con't write code like this typeof(A<>).IsAssignableFrom(aa.GetType());//return false Trace(typeof(object).IsAssignableFrom(typeof(string)));//true Trace(typeof(A<>).IsAssignableFrom(typeof(A)));//false AAA aaa = new AAA(); Trace("Use IsTypeOf:"); Trace(IsTypeOf(aaa, typeof(A<>))); Trace(IsTypeOf(aaa, typeof(AA))); Trace(IsTypeOf(aaa, typeof(AAA<>))); Trace("Use IsAssignableFrom from stackoverflow - not right:"); Trace(IsAssignableFrom(typeof(A), typeof(A<>))); // error Trace(IsAssignableFrom(typeof(AA), typeof(A<>))); Trace(IsAssignableFrom(typeof(AAA), typeof(A<>))); Trace("Use IsAssignableToGenericType:"); Trace(IsAssignableToGenericType(typeof(A), typeof(A<>))); Trace(IsAssignableToGenericType(typeof(AA), typeof(A<>))); Trace(IsAssignableToGenericType(typeof(AAA), typeof(A<>))); } static void Trace(object log){ Console.WriteLine(log); } public static bool IsTypeOf(Object o, Type baseType) { if (o == null || baseType == null) { return false; } bool result = baseType.IsInstanceOfType(o); if (result) { return result; } return IsAssignableFrom(o.GetType(), baseType); } public static bool IsAssignableFrom(Type extendType, Type baseType) { while (!baseType.IsAssignableFrom(extendType)) { if (extendType.Equals(typeof(object))) { return false; } if (extendType.IsGenericType && !extendType.IsGenericTypeDefinition) { extendType = extendType.GetGenericTypeDefinition(); } else { extendType = extendType.BaseType; } } return true; } //from stackoverflow - not good enough public static bool IsAssignableToGenericType(Type givenType, Type genericType) { var interfaceTypes = givenType.GetInterfaces(); foreach (var it in interfaceTypes) if (it.IsGenericType) if (it.GetGenericTypeDefinition() == genericType) return true; Type baseType = givenType.BaseType; if (baseType == null) return false; return baseType.IsGenericType && baseType.GetGenericTypeDefinition() == genericType || IsAssignableToGenericType(baseType, genericType); } } class A{} class AA : A{} class AAA : AA{} }
你需要比较包含的types。 请参阅: 如何从generics类或方法的成员获取T的types?
换句话说,我认为你需要检查generics类包含的types是否可赋值,而不是generics类本身。