2011-03-28 36 views
40

使用反射,我试图找到从给定基类继承的一组类型。找出简单的类型并不需要很长时间,但是当涉及到泛型时,我却难以理解。使用IsAssignableFrom和'open'泛型类型

对于这段代码,第一个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>(); 
    } 
} 

那么,如何在运行时确定一个泛型类型定义是否是从另一个派生?

+2

最终的分配只涉及'基因ric2' ... – 2011-03-28 15:33:28

+0

可能的重复[如何检测如果类型是另一种类型](http://stackoverflow.com/questions/74616/how-to-detect-if-type-is-another-generic-type ) – 2011-03-28 15:35:13

+0

@Daniel Hilgarth - 谢谢!当我在发布前清理示例代码时,我错过了这一点。它仍然编译时,分配是通用的1 cc = new generic2 (); – ThatBlairGuy 2011-03-28 15:37:31

回答

64

answer to another question

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

(如果你喜欢的答案,请给予好评链接的答案,因为代码是不是我的。)

+0

谢谢!这正是我正在寻找的。我在前面看时没有注意到其他问题。 – ThatBlairGuy 2011-03-28 18:32:18

+2

在下面的情况下,这种方法可能是错误的:IsAssignableToGenericType(typeof(A ),typeof(A <>)); //返回false – 2011-09-23 14:49:41

+0

但是,这个答案很好,当你使用这个虽然。我用它,使bool表达式工作,然后我什么都做不了,因为我可以投我的对象,以便使用它...我不得不介绍一个接口,我可以简单地检查与'是'... – Jaap 2012-05-23 19:32:00

8

你贴不回令人惊讶的结果确切的代码。

这是说“假”:

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

不同的是,开放式泛型类型不能有实例,这样一个不是“分配”到其他。

docs

返回true如果c和当前 Type表示相同的类型,或者如果 当前Type处于c的 继承层次,或者如果 当前Typec执行的接口 ,或者如果c是 通用类型参数和当前 Type代表c的 约束之一。 false如果没有 这些条件属实,或者cnull

在这种情况下,显然这些条件都不是真的。而且还有一个额外注:

泛型类型定义是不 分配从封闭构造 类型。也就是说,您不能将 封闭构造类型 MyGenericList<int>MyGenericList(Of Integer)在Visual Basic中)分配给类型为MyGenericList<T>的 变量。

+1

好的解释! – 2016-09-21 22:33:03

2

在下列情况下使用康拉德·鲁道夫提供的可能是错的,就像方法: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; 
} 

测试的情况下,看到Using IsAssignableFrom with C# generics查看详细

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{} 
} 
+2

注意:此答案不处理通用接口。 – phloopy 2013-08-14 20:19:29