Получить все производные типы типа
Есть ли лучший (более эффективный или более удобный код;) способ найти все производные типы типа?
В настоящее время я использую что-то вроде:
- получить все типы в используемых сборках
- проверьте мой тип со всеми этими типами, если это "IsAssignable"
Мне было интересно, лучший ли способ сделать это?
Ответы
Ответ 1
I один раз использовал этот Linq-метод для получения всех типов, наследуемых от базового типа B:
var listOfBs = (from domainAssembly in AppDomain.CurrentDomain.GetAssemblies()
from assemblyType in domainAssembly.GetTypes()
where typeof(B).IsAssignableFrom(assemblyType)
select assemblyType).ToArray();
РЕДАКТИРОВАТЬ. Похоже, что это больше похоже на rep (таким образом, больше просмотров), позвольте мне добавить более подробную информацию:
- Как указано выше, этот метод использует Reflection для каждого вызова. Поэтому при повторном использовании метода для одного и того же типа,
можно было бы сделать его намного более эффективным, загрузив его один раз.
- Как Антон предлагает, может быть, вы сможете (микро) оптимизировать его с помощью
domainAssembly.GetExportedTypes()
для получения только общедоступных типов (если это все, что вам нужно).
- Как Noldorin упоминает,
Type.IsAssignable
также получит исходный (не производный) тип. (Type.IsSubclassOf
не будет, но Type.IsSubclassOf
не будет работать, если базовый тип является интерфейсом).
- Может потребоваться/нужно проверить "реальный" класс:
&& ! assemblyType.IsAbstract
. (Обратите внимание, что все интерфейсы считаются абстрактными, см. MSDN.)
Ответ 2
Я уверен, что предложенный вами метод станет более простым способом найти все производные типы. Родительские классы не хранят никакой информации о том, что их подклассы (было бы довольно глупо, если бы они это сделали), а это означает, что здесь не избежать поиска по всем типам.
Только рекомендация заключается в использовании метода Type.IsSubclassOf
вместо Type.IsAssignable
, чтобы проверить, является ли конкретный тип производным от другого. Тем не менее, возможно, есть причина, по которой вам нужно использовать Type.IsAssignable
(например, он работает с интерфейсами).
Ответ 3
Единственная оптимизация, которую вы можете выжать из этого, - использовать Assembly.GetExportedTypes()
для извлечения только общедоступных типов, если это произойдет. Кроме этого, нет возможности ускорить процесс. LINQ может помочь с удобочитаемой стороной вещей, но не с точки зрения производительности.
Вы можете сделать короткое замыкание, чтобы избежать ненужных вызовов IsAssignableFrom
, которые, по мнению Reflector, довольно дороги, сначала проверяя, является ли тип, о котором идет речь, требуемым "классом". То есть вы ищете только классы, нет смысла тестировать перечисления или массивы для "назначаемости".
Ответ 4
Я думаю, что нет лучшего или прямого пути.
Лучше: используйте IsSubclassOf
вместо IsAssignable
.
Ответ 5
Asuming baseType содержит объект System.Type, который вы хотите проверить, и matchType содержит объект System.Type с типом текущей итерации (через цикл foreach или любой другой):
Если вы хотите проверить wheather matchType получен из класса, представленного baseType, я бы использовал
matchType.IsSubclassOf(baseType)
И если вы хотите проверить wheather matchType реализует интерфейс, представленный baseType, я бы использовал
matchType.GetInterface(baseType.ToString(), false) != null
Конечно, я бы сохранил baseType.ToString() как глобальную переменную, поэтому мне не нужно было бы все время ее вызывать. И так как вам, вероятно, понадобится это в контексте, где у вас много типов, вы также можете рассмотреть возможность использования System.Threading.Tasks.Parallel.ForEach-Loop для повторения всех ваших типов...
Ответ 6
Если вы просто заинтересованы в просмотре, то .NET Reflector сможет это сделать. Однако это не так реально. Вы хотите, чтобы все типы были в загруженных в настоящее время сборках? Ассембли, на которые ссылается исполнительная сборка? Существует много разных способов получить список типов, и написать что-то, что будет учитывать (и предоставить варианты), было бы довольно большой ценой с относительно низкой выгодой.
Что вы пытаетесь сделать? Вероятно, лучший (или, по крайней мере, более эффективный) способ сделать это.
Ответ 7
Просто создайте статический словарь производных типов при запуске и выполните поиск по нему. Например. public static Dictionay<Type, Type[]> DerivedTypes { get;set; }
public static Dictionay<Type, Type[]> DerivedTypes { get;set; }
где Type - любой тип, который вы хотите включить в поиск, а Type [] - список производных типов. Заполняйте словарь при запуске приложения и используйте его в течение всей жизни приложения.
Ответ 8
Я закончил тем, что использовал код, который дал главный ответ. Единственное, я хотел, чтобы код был более читабельным, поэтому я написал в основном то же самое, но вместо этого:
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
), поэтому я также исключаю производные абстрактные классы.