2011-03-28 37 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