Usando a reflexão, como posso obter todos os tipos que implementam uma interface com C # 3.0 / .NET 3.5 com o mínimo de código e minimizando iterações?
É isso que quero reescrever:
foreach (Type t in this.GetType().Assembly.GetTypes())
if (t is IMyInterface)
; //do stuff
Respostas:
O meu seria isso em c # 3.0 :)
Basicamente, a menor quantidade de iterações sempre será:
fonte
.Where(p => type.IsAssignableFrom(p) && !p.IsInterface);
para filtrá-la (oup.IsClass
).List<string>
não é implementado,IEnumerable<object>
mas esse método retornará verdadeiro no .Net 4.0 devido à covariância que está realmente errada. A resposta correta está aqui #.Where(p => type.IsAssignableFrom(p) && p.IsClass && !p.IsAbstract
Isso funcionou para mim. Ele percorre as classes e verifica se elas são derivadas de myInterface
fonte
Para encontrar todos os tipos em um assembly que implementa a interface IFoo:
Observe que a sugestão de Ryan Rinaldi estava incorreta. Ele retornará 0 tipos. Você não pode escrever
porque type é uma instância System.Type e nunca será do tipo IFoo. Em vez disso, você verifica se o IFoo é atribuível a partir do tipo. Isso obterá os resultados esperados.
Além disso, a sugestão de Adam Wright, que atualmente está marcada como resposta, também está incorreta e pelo mesmo motivo. No tempo de execução, você verá 0 tipos retornados, porque todas as instâncias System.Type não eram implementadores do IFoo.
fonte
Compreendo que essa é uma pergunta muito antiga, mas pensei em adicionar outra resposta para futuros usuários, pois todas as respostas até o momento usam alguma forma de
Assembly.GetTypes
.Embora GetTypes () realmente retorne todos os tipos, isso não significa necessariamente que você possa ativá-los e, portanto, potencialmente lançar a
ReflectionTypeLoadException
.Um exemplo clássico de não poder ativar um tipo seria quando o tipo retornado é
derived
de,base
masbase
é definido em um assembly diferente daquele dederived
, um assembly ao qual o assembly de chamada não faz referência.Então diga que temos:
Se em
ClassC
que estáAssemblyC
, faremos algo conforme a resposta aceita:Então ele jogará a
ReflectionTypeLoadException
.Isso ocorre porque sem uma referência a
AssemblyA
emAssemblyC
que você não seria capaz de:Em outras palavras,
ClassB
não é carregável, o que é algo que a chamada para GetTypes verifica e ativa.Portanto, para qualificar com segurança o conjunto de resultados para tipos carregáveis, de acordo com este artigo de Phil Haacked Obter todos os tipos em um código Assembly e Jon Skeet, você faria algo como:
E depois:
fonte
CreateInstance
para todos eles, e uma exceção foi lançada ao tentar criar a interface real (o que me deixou confuso por um tempo quando pensei que a interface real estava fora do caminho nesta solução). Então mudei o código paraGetLoadableTypes(assembly).Where(interfaceType.IsAssignableFrom).Where(t => !(t.Equals(interfaceType))).ToList();
.Outras respostas aqui são usadas
IsAssignableFrom
. Você também pode usarFindInterfaces
noSystem
espaço para nome, conforme descrito aqui .Aqui está um exemplo que verifica todos os assemblies na pasta do assembly em execução no momento, procurando por classes que implementam uma certa interface (evitando o LINQ para maior clareza).
Você pode configurar uma lista de interfaces se desejar corresponder a mais de uma.
fonte
faça um loop em todos os assemblies carregados, faça um loop em todos os seus tipos e verifique se eles implementam a interface.
algo como:
fonte
Isso funcionou para mim (se você deseja excluir tipos de sistema na pesquisa):
fonte
Editar: Acabei de ver a edição para esclarecer que a pergunta original era para a redução de iterações / código e isso é muito bom como exercício, mas em situações do mundo real, você deseja a implementação mais rápida, independentemente de quão legal é o LINQ subjacente.
Aqui está o meu método Utils para percorrer os tipos carregados. Ele lida com classes regulares e interfaces, e a opção excludeSystemTypes acelera enormemente as coisas se você estiver procurando implementações em sua base de código própria / de terceiros.
Não é bonito, eu admito.
fonte
excludeSystemTypes
duas vezes em umif
?Outra resposta não estava funcionando com uma interface genérica .
Nesse caso, basta substituir typeof (ISomeInterface) por typeof (T).
Então com
nós temos todas as assembléias
é usado para excluir a interface e as abstratas e
tê-los em uma lista.
fonte
Não há uma maneira fácil (em termos de desempenho) de fazer o que você deseja fazer.
O Reflection trabalha principalmente com montagens e tipos, portanto você terá que obter todos os tipos de montagem e consultá-los para obter a interface correta. Aqui está um exemplo:
Isso fornecerá a você todos os tipos que implementam o IMyInterface no Assembly MyAssembly
fonte
Ainda melhor ao escolher o local da montagem. Filtre a maioria dos assemblies se você souber que todas as suas interfaces implementadas estão dentro do mesmo Assembly.DefinedTypes.
Por Can Bilgin
fonte
O método OfType Linq pode ser usado exatamente para esse tipo de cenário:
https://docs.microsoft.com/fr-fr/dotnet/api/system.linq.enumerable.oftype?view=netframework-4.8
fonte
Já existem muitas respostas válidas, mas eu gostaria de adicionar outra implementação como uma extensão de tipo e uma lista de testes de unidade para demonstrar diferentes cenários:
Este algoritmo suporta os seguintes cenários:
fonte
fonte
Eu tenho exceções no código linq, então faço dessa maneira (sem uma extensão complicada):
fonte
Você pode usar algum LINQ para obter a lista:
Mas sério, isso é mais legível?
fonte