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
mas base
é definido em um assembly diferente daquele de derived
, um assembly ao qual o assembly de chamada não faz referência.
Então diga que temos:
Class A // in AssemblyA
Class B : Class A, IMyInterface // in AssemblyB
Class C // in AssemblyC which references AssemblyB but not AssemblyA
Se em ClassC
que está AssemblyC
, faremos algo conforme a resposta aceita:
var type = typeof(IMyInterface);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => type.IsAssignableFrom(p));
Então ele jogará a ReflectionTypeLoadException
.
Isso ocorre porque sem uma referência a AssemblyA
em AssemblyC
que você não seria capaz de:
var bType = typeof(ClassB);
var bClass = (ClassB)Activator.CreateInstance(bType);
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:
public static class TypeLoaderExtensions {
public static IEnumerable<Type> GetLoadableTypes(this Assembly assembly) {
if (assembly == null) throw new ArgumentNullException("assembly");
try {
return assembly.GetTypes();
} catch (ReflectionTypeLoadException e) {
return e.Types.Where(t => t != null);
}
}
}
E depois:
private IEnumerable<Type> GetTypesWithInterface(Assembly asm) {
var it = typeof (IMyInterface);
return asm.GetLoadableTypes().Where(it.IsAssignableFrom).ToList();
}