Используя отражение, как я могу получить все типы, которые реализуют интерфейс с C # 3.0 / .NET 3.5 с наименьшим количеством кода и минимизируя итерации?
Вот что я хочу переписать:
foreach (Type t in this.GetType().Assembly.GetTypes())
if (t is IMyInterface)
; //do stuff
Ответы:
Мой был бы это в c # 3.0 :)
По сути, наименьшее количество итераций всегда будет:
источник
.Where(p => type.IsAssignableFrom(p) && !p.IsInterface);
чтобы отфильтровать ее (илиp.IsClass
).List<string>
, не реализует,IEnumerable<object>
но этот метод вернет true в .Net 4.0 из-за ковариации, которая на самом деле неверна. Правильный ответ здесь.Where(p => type.IsAssignableFrom(p) && p.IsClass && !p.IsAbstract
Это сработало для меня. Он проходит по классам и проверяет, получены ли они из myInterface
источник
Чтобы найти все типы в сборке, реализующей интерфейс IFoo:
Обратите внимание, что предложение Райана Ринальди было неверным. Он вернет 0 типов. Вы не можете написать
потому что тип является экземпляром System.Type и никогда не будет иметь тип IFoo. Вместо этого вы проверяете, присваивается ли IFoo тип. Это даст ожидаемые результаты.
Кроме того, предложение Адама Райта, которое в настоящее время помечено как ответ, также неверно и по той же причине. Во время выполнения вы увидите, что возвращаются 0 типов, потому что все экземпляры System.Type не были реализациями IFoo.
источник
Я ценю, что это очень старый вопрос, но я подумал, что добавлю еще один ответ для будущих пользователей, так как все ответы на сегодняшний день используют ту или иную форму
Assembly.GetTypes
.Хотя GetTypes () действительно возвращает все типы, это не обязательно означает, что вы можете активировать их и, таким образом, потенциально можете генерировать a
ReflectionTypeLoadException
.Классическим примером того, что невозможно активировать тип, может быть случай, когда возвращаемый тип взят
derived
из,base
ноbase
определен в сборке, отличной отderived
сборки, на которую не ссылается вызывающая сборка.Так сказать, у нас есть:
Если в
ClassC
которомAssemblyC
мы находимся, то делаем что-то согласно принятому ответу:Тогда это бросит
ReflectionTypeLoadException
.Это происходит потому , что без ссылки
AssemblyA
наAssemblyC
вас не будет в состоянии:Другими словами
ClassB
, не загружается, что проверяет и генерирует вызов GetTypes.Таким образом, чтобы безопасно квалифицировать набор результатов для загружаемых типов, в соответствии с этой статьей Фила Хаакеда « Получить все типы в сборке и код Jon Skeet» вместо этого вы должны сделать что-то вроде:
А потом:
источник
CreateInstance
для всех, и было выдано исключение, когда он пытался создать реальный интерфейс (что на какое-то время меня смутило, когда я подумал, что в этом решении не работает настоящий интерфейс). Поэтому я изменил код наGetLoadableTypes(assembly).Where(interfaceType.IsAssignableFrom).Where(t => !(t.Equals(interfaceType))).ToList();
.Другие ответы здесь используют
IsAssignableFrom
. Вы также можете использоватьFindInterfaces
изSystem
пространства имен, как описано здесь .Вот пример, который проверяет все сборки в папке исполняемой в данный момент сборки, ищет классы, которые реализуют определенный интерфейс (избегая LINQ для ясности).
Вы можете настроить список интерфейсов, если вы хотите соответствовать более чем одному.
источник
цикл по всем загруженным сборкам, цикл по всем их типам и проверка, реализуют ли они интерфейс.
что-то вроде:
источник
Это сработало для меня (если вы хотите исключить системные типы из поиска):
источник
Редактировать: я только что видел редактирование, чтобы уточнить, что исходный вопрос был для сокращения итераций / кода, и это все хорошо, как упражнение, но в реальных ситуациях вам понадобится самая быстрая реализация, независимо от того, о том, как здорово выглядит лежащий в основе LINQ.
Вот мой метод Utils для перебора загруженных типов. Он обрабатывает обычные классы, а также интерфейсы, а опция excludeSystemTypes значительно ускоряет работу, если вы ищете реализации в собственной / сторонней кодовой базе.
Это не красиво, я признаю.
источник
excludeSystemTypes
дважды в одномif
?Другой ответ не работал с универсальным интерфейсом .
Это делает, просто замените typeof (ISomeInterface) на typeof (T).
Так с
мы получаем все сборки
используется для исключения интерфейса и абстрактных и
иметь их в списке.
источник
Нет простого способа (с точки зрения производительности) сделать то, что вы хотите.
Reflection работает в основном со сборками и типами, поэтому вам нужно получить все типы сборок и запросить их для правильного интерфейса. Вот пример:
Это даст вам все типы, которые реализуют IMyInterface в сборке MyAssembly
источник
Еще лучше при выборе места сборки. Отфильтруйте большинство сборок, если вы знаете, что все реализованные интерфейсы находятся в одном и том же Assembly.DefinedTypes.
Кан Билгин
источник
Метод OfType Linq может быть использован именно для таких сценариев:
https://docs.microsoft.com/fr-fr/dotnet/api/system.linq.enumerable.oftype?view=netframework-4.8
источник
Уже есть много правильных ответов, но я бы хотел добавить другую реализацию как расширение типа и список модульных тестов, чтобы продемонстрировать различные сценарии:
Этот алгоритм поддерживает следующие сценарии:
источник
источник
Я получил исключения в linq-коде, поэтому я делаю это так (без сложного расширения):
источник
Вы можете использовать LINQ, чтобы получить список:
Но действительно ли это более читабельно?
источник