Получить все производные типы типа

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

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

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

7 ответов

Однажды я использовал этот 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.)

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

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

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

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

Предполагается, что 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 для перебора всех ваших типов...

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

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

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

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) поэтому я также исключаю производные абстрактные классы.

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

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

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

Другие вопросы по тегам