Получить все производные типы типа - PullRequest
54 голосов
/ 13 мая 2009

Есть ли лучший (более производительный или более хороший код;) способ найти все производные типы типов? В настоящее время я использую что-то вроде:

  1. получить все типы использованных сборок
  2. проверить мой тип со всеми этими типами, если это 'IsAssignable'

Мне было интересно, есть ли лучший способ сделать это?

Ответы [ 8 ]

61 голосов
/ 16 июля 2013

I один раз использовал этот Linq-метод для получения всех типов, наследуемых от базового типа B:

    var listOfBs = (from domainAssembly in AppDomain.CurrentDomain.GetAssemblies()
                    from assemblyType in domainAssembly.GetTypes()
                    where typeof(B).IsAssignableFrom(assemblyType)
                    select assemblyType).ToArray();

РЕДАКТИРОВАТЬ : Поскольку кажется, что это все еще дает больше повторений (и, следовательно, больше просмотров), позвольте мне добавить еще несколько деталей:

  • Как указано в ссылке выше, этот метод использует Reflection при каждом вызове. Поэтому при многократном использовании метода для одного и того же типа, возможно, можно сделать его намного эффективнее, загрузив его один раз.
  • Как подсказывает Антон , возможно, вы могли бы (микро) оптимизировать его, используя domainAssembly.GetExportedTypes() извлекать только общедоступные типы (если это все, что вам нужно).
  • Как упоминает Нолдорин , Type.IsAssignable также получит исходный (не производный) тип. (Type.IsSubclassOf не будет, но Type.IsSubclassOf не будет работать, если базовый тип является интерфейсом).
  • Можно захотеть / нужно проверить «настоящий» класс: && ! assemblyType.IsAbstract. (Обратите внимание, что все интерфейсы считаются абстрактными, см. MSDN .)
10 голосов
/ 13 мая 2009

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

Единственная рекомендация - использовать метод Type.IsSubclassOf вместо Type.IsAssignable, чтобы проверить, является ли определенный тип производным от другого. Тем не менее, возможно, есть причина, по которой вам нужно использовать Type.IsAssignable (например, он работает с интерфейсами).

7 голосов
/ 13 мая 2009

Единственная оптимизация, которую вы можете выжать из этого, - это использовать Assembly.GetExportedTypes() для извлечения только публично видимых типов, если это так. Кроме этого, нет способа ускорить процесс. LINQ может помочь с читабельностью, но не с точки зрения производительности.

Вы можете сделать некоторое короткое замыкание, чтобы избежать ненужных вызовов на IsAssignableFrom, который, по мнению Reflector, довольно дорогой, сначала проверив, имеет ли рассматриваемый тип требуемый "класс". То есть, вы ищете только классы, нет смысла тестировать перечисления или массивы для «назначаемости».

4 голосов
/ 21 июня 2012

Предполагается, что baseType содержит объект System.Type, который вы хотите проверить, а matchType содержит объект System.Type с типом текущей итерации (через цикл foreach или любой другой):

Если вы хотите проверить, является ли matchType производным от класса, представленного baseType, я бы использовал

matchType.IsSubclassOf(baseType)

И если вы хотите проверить, соответствует ли matchType интерфейсу, представленному baseType, я бы использовал

matchType.GetInterface(baseType.ToString(), false) != null

Конечно, я бы сохранял baseType.ToString () как глобальную переменную, поэтому мне не нужно вызывать ее постоянно. И поскольку вам, вероятно, понадобится это в контексте, где у вас много типов, вы можете также рассмотреть возможность использования System.Threading.Tasks.Parallel.ForEach-Loop для итерации всех ваших типов ...

4 голосов
/ 13 мая 2009

Я думаю, что нет лучшего или прямого пути.

Лучше: используйте IsSubclassOf вместо IsAssignable.

1 голос
/ 13 мая 2009

Если вы просто интересуетесь просмотром, то .NET Reflector имеет возможность сделать это. Однако это не то, что действительно возможно. Хотите ли вы все типы, которые находятся в загруженных сборках? Сборки, на которые ссылается исполняющая сборка? Есть много разных способов получить список типов, и написание чего-либо, что учитывало бы (и предоставляло варианты), было бы довольно большой ценой с относительно невысокой выгодой.

Что ты пытаешься сделать? Вероятно, есть лучший (или, по крайней мере, более эффективный) способ сделать это.

0 голосов
/ 17 мая 2019

Я закончил тем, что использовал код, который дал главный ответ. Единственное, я хотел, чтобы код был более читабельным, поэтому я написал в основном то же самое, но вместо этого:

var derived_types = new List<Type>();
foreach (var domain_assembly in AppDomain.CurrentDomain.GetAssemblies())
{
  var assembly_types = domain_assembly.GetTypes()
    .Where(type => type.IsSubclassOf(typeof(MyType)) && !type.IsAbstract);

  derived_types.AddRange(assembly_types);
}

В моем случае я использовал type.IsSubClassOf(MyType), потому что я хотел только производные типы, исключая базовый класс, как упомянуто выше. Мне также нужно, чтобы производные типы не были абстрактными (!type.IsAbstract), поэтому я также исключаю производные абстрактные классы.

0 голосов
/ 21 января 2019

Просто создайте статический словарь производных типов при запуске и выполните поиск по нему. Например. public static Dictionay<Type, Type[]> DerivedTypes { get;set; } где Type - любой тип, который вы хотите включить в поиск а Type [] - список производных типов. Заполняйте словарь при запуске приложения и используйте его в течение всей жизни приложения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...