2015-03-17 4 views
2

я написал небольшой метод список унаследованных типов, но он не работает с TreeNode, например:Получение списка Наследование типов не работает для всех типов

Пусть это классы:

class B { } 
class A : B { } 
class C :TreeNode { } 

И потом:

GetInheritedTypes(typeof(A)); //typeof(B) 
GetInheritedTypes(typeof(C)); // 0 items 

Способ перечислить их:

List<Type> GetInheritedTypes(Type baseType) 
{ 
    return Assembly.GetAssembly(baseType) 
        .GetTypes() 
        .Where(type => type != baseType && type.IsAssignableFrom(baseType)) 
        .ToList(); 
} 

Почему GetInheritedTypes(typeof(C)) возвращает 0 штук вместо Typeof(TreeNode)?

+1

Являются ли 'C' и' TreeNode' объявленными в той же сборке? – MarcinJuraszek

+0

Почему вы не просто используете 'type.BaseType'? Это даст вам базовый тип типа без перечисления каждого типа в сборке. – Jamiec

+2

@MarcinJuraszek: Нет, это не так, если Джек не работает над добавлением типа C в System.Windows.Forms.DLL. –

ответ

9

Почему GetInheritedTypes (typeof (C)) возвращает 0 элементов вместо Typeof (TreeNode)?

Потому что TreeNode нет в той же сборке, что и C. Ваш запрос «из всех типов в той же сборке, что и C, дает мне те, которые C присваивается».

Я подозреваю, однако, что фактическая проблема заключается в:

Как перечислить все базовые типы данного типа?

Вы делаете не сделать поиск по всем типам в сборке и проверить, какие из них являются назначаемыми. Это похоже на попытку выяснить, кто твоя мама, спрашивая каждого человека в вашем городе: «Ты мать Джека?» вместо того, чтобы спросить Джека «кто твоя мама?».

Нечто подобное было бы намного лучше:

public static IEnumerable<Type> BaseTypes(this Type type) 
{ 
    if (type == null) throw new ArgumentNullException("type"); 
    Type baseType = type; 
    while(true) 
    { 
     baseType = baseType.BaseType; 
     if (baseType == null) 
      break; 
     yield return baseType; 
    } 
} 

Комментатор спрашивает

что, если вы хотите, чтобы получить все реализованные интерфейсы?

Звоните GetInterfaces() на тип объекта.

(ранняя версия этого поста предложил получать транзитивное замыкание интерфейсов, я совсем забыл, что GetInterfaces уже делает это.)

Как еще был мой исходный код сломана?

Ну, предположим, например, у вас есть тип

class D<T> {} 

и класс

class E : D<int> {} 

Теперь вы спросите «дали E, перечислить все типы X в сборке, так что значение типа E может быть присвоено переменной типа X ". Ну, D<T> находится в сборке; есть D<T> такой тип? №. E присваивается переменной типа D<int>, а не переменной типа D<T>.

Отношение «присваиваемые» и отношения «наследует от» имеют довольно много перекрытий, но они совсем не относятся к отношениям, поэтому не делайте вид, что они есть.

+0

Что делать, если тип реализует несколько интерфейсов? – moarboilerplate

+0

Удивительный пример. Я предполагаю, что вы могли бы получить все реализованные типы (исключая назначаемые общие типы, базовые типы + интерфейсы), выполняя что-то вроде 'relation = t => t.GetInterfaces(). Concat (t.BaseType == null? Enumerable .Empty (): new [] {t.BaseType}); 'correct? – moarboilerplate

+0

@moarboilerplate: Я удалил свой удивительный пример, потому что понял, что это не нужно. (Я думал о реализации Roslyn отношения «все интерфейсы», а не о реализации Reflection.) Но да, вы можете получить «транзитивное закрытие всех базовых типов и интерфейсов», как вы предлагаете. –

1

Вы только перечисляете классы в пределах той же сборки, что и C, и предположительно TreeNode находится в другой сборке.

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