Подтвердить что ты не робот

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

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

  • получить все типы в используемых сборках
  • проверьте мой тип со всеми этими типами, если это "IsAssignable"

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

4b9b3361

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