Вопрос основан на примере MSDN .
Допустим, у нас есть несколько классов C # с HelpAttribute в автономном настольном приложении. Можно ли перечислить все классы с таким атрибутом? Имеет ли смысл распознавать классы таким образом? Пользовательский атрибут будет использоваться для отображения списка возможных вариантов меню, выбор пункта приведет к отображению на экране экземпляра такого класса. Количество классов / предметов будет расти медленно, но, таким образом, мы можем избежать их перечисления в другом месте, я думаю.
Select
метод расширения, и компилятор сгенерирует конечный автомат, как если бы вы вызвали егоSelect
из-за вашего использованияyield return
. Наконец, любой выигрыш в производительности, который может быть получен в большинстве случаев, является микрооптимизацией.Ну, вам придется перечислять все классы во всех сборках, которые загружены в текущий домен приложения. Для этого необходимо вызвать
GetAssemblies
метод вAppDomain
экземпляре для текущего домена приложения.Оттуда вы будете вызывать
GetExportedTypes
(если вам нужны только открытые типы) илиGetTypes
для каждого из нихAssembly
получить типы, содержащиеся в сборке.Затем вы вызываете
GetCustomAttributes
метод расширения для каждогоType
экземпляра, передавая тип атрибута, который вы хотите найти.Вы можете использовать LINQ, чтобы упростить это для вас:
Приведенный выше запрос даст вам каждый тип с примененным к нему атрибутом, а также экземпляр присвоенного ему атрибута (ов).
Обратите внимание, что если в домен приложения загружено большое количество сборок, эта операция может быть дорогой. Вы можете использовать Parallel LINQ, чтобы сократить время операции, например:
Фильтрация по конкретному
Assembly
проста:И если в сборке много типов, вы можете снова использовать Parallel LINQ:
источник
Другие ответы ссылаются на GetCustomAttributes . Добавление этого в качестве примера использования IsDefined
источник
Как уже говорилось, рефлексия - это путь. Если вы собираетесь это часто называть, я настоятельно рекомендую кэшировать результаты, поскольку рефлексия, особенно перечисление в каждом классе, может быть довольно медленной.
Это фрагмент моего кода, который проходит через все типы во всех загруженных сборках:
источник
Это повышение производительности поверх принятого решения. Итерации, хотя все классы могут быть медленными, потому что их так много. Иногда вы можете отфильтровать всю сборку, не глядя ни на один из ее типов.
Например, если вы ищете атрибут, который вы объявили сами, вы не ожидаете, что какие-либо системные библиотеки DLL будут содержать какие-либо типы с этим атрибутом. Свойство Assembly.GlobalAssemblyCache - это быстрый способ проверки системных библиотек DLL. Когда я попробовал это в реальной программе, я обнаружил, что могу пропустить 30 101 тип, и мне нужно только проверить 1 983 типов.
Другой способ фильтрации - использовать Assembly.ReferencedAssemblies. Предположительно, если вам нужны классы с определенным атрибутом, и этот атрибут определен в конкретной сборке, вам нужно заботиться только об этой сборке и других сборках, которые на нее ссылаются. В моих тестах это помогло немного больше, чем проверка свойства GlobalAssemblyCache.
Я объединил оба из них и получил это еще быстрее. Код ниже включает оба фильтра.
источник
В случае ограничений Portable .NET должен работать следующий код:
или для большого количества сборок, использующих петлевое состояние
yield return
:источник
Мы можем улучшить ответ Эндрю и преобразовать все это в один запрос LINQ.
источник