2015-09-15 2 views
3

У меня есть общий класс со многими подтипами:Получение списка подтипов общего класса

public abstract class MyClass<T> : MyBaseClass where T : class 
{...} 

public class MySubClassA : MyClass<A> 
{...} 

public class MySubClassB : MyClass<B> 
{...} 

есть простой способ для поиска подклассы MyClass и получить IEnumerable<Type> содержащий MySubClassA и MySubClassB?

Я использовал этот метод прежде, но я не уверен, как адаптировать его для использования с обобщениями:

public static IEnumerable<Type> GetSubTypesOf(Type t, bool baseAssemblyOnly = false) 
{ 
    List<Type> types = new List<Type>(); 
    Assembly[] searchAssemblies = baseAssemblyOnly 
     ? new[] { Assembly.GetAssembly(t) } 
     : AppDomain.CurrentDomain.GetAssemblies(); 
    foreach (Assembly a in searchAssemblies) 
    { 
     types.AddRange(a.GetTypes() 
         .Where(myType => myType.IsClass 
             && !myType.IsAbstract 
             && myType.IsSubclassOf(t))); 
    } 
    return types; 
} 
+0

Я не ясно, почему код, который вы размещены не на самом деле работает. Похоже, вы бы назвали GetSubTypesOf (typeof (MyClass )) правильно? –

ответ

2

Проблема заключается в том, что, когда вы передаете typeof(MyClass<>) для параметра t, вы не пропускание конкретизированного общего типа, но общий типа определения. Это означает, что ни один из ваших классов не ответит на IsSubclassOf(t).

Вы можете исправить код следующим образом:

List<Type> types = searchAssemblies 
    .SelectMany(a => 
     a.GetTypes() 
     .Where(myType => myType.IsClass && !myType.IsAbstract && HasGenericBase(myType, t)) 
    ).ToList(); 
... 
private static bool HasGenericBase(Type myType, Type t) { 
    Debug.Assert(t.IsGenericTypeDefinition); 
    while (myType != typeof(object)) { 
     if (myType.IsGenericType && myType.GetGenericTypeDefinition() == t) { 
      return true; 
     } 
     myType = myType.BaseType; 
    } 
    return false; 
} 
3

Это немного сложнее, так как вы должны искать базовые типы типа, чтобы найти один из которых соответствует определению открытого общего типа MyClass<>. Вы можете определить несколько вспомогательных методов:

public static IEnumerable<Type> BaseTypesOf(Type t) 
{ 
    while (t != null) 
    { 
     yield return t; 
     t = t.BaseType; 
    } 
} 

public static Type FindGenericBaseTypeOf(Type t, Type openType) 
{ 
    return BaseTypesOf(t) 
     .FirstOrDefault(bt => bt.IsGenericType && bt.GetGenericTypeDefinition() == openType); 
} 

, то вы можете применить их к входной последовательности типов для поиска, например,

var types = Assembly.GetExecutingAssembly().GetTypes() 
    .Where(t => t.IsClass && !t.IsAbstract) 
    .Select(t => new { Type = t, GenericBase = FindGenericBaseTypeOf(t, typeof(MyClass<>)) }) 
    .Where(ts => ts.GenericBase != null) 
    .Select(ts => ts.GenericBase.GetGenericArguments().First()) 
    .ToArray(); 
+0

Ключ GetGenericTypeDefinition(): https://msdn.microsoft.com/en-us/library/system.type.getgenerictypedefinition.aspx –

Смежные вопросы