Aprecio que esta es una pregunta muy antigua, pero pensé que agregaría otra respuesta para futuros usuarios, ya que todas las respuestas hasta la fecha usan alguna forma de Assembly.GetTypes
.
Si bien GetTypes () realmente devolverá todos los tipos, no necesariamente significa que podría activarlos y, por lo tanto, podría arrojar a ReflectionTypeLoadException
.
Un ejemplo clásico para no poder activar un tipo sería cuando el tipo devuelto es derived
de base
pero base
se define en un ensamblaje diferente del de derived
, un ensamblaje al que el ensamblado que llama no hace referencia.
Entonces digamos que tenemos:
Class A // in AssemblyA
Class B : Class A, IMyInterface // in AssemblyB
Class C // in AssemblyC which references AssemblyB but not AssemblyA
Si en ClassC
cuál está adentro AssemblyC
, entonces hacemos algo según la respuesta aceptada:
var type = typeof(IMyInterface);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => type.IsAssignableFrom(p));
Entonces arrojará un ReflectionTypeLoadException
.
Esto se debe a que sin una referencia a AssemblyA
en AssemblyC
que no sería capaz de:
var bType = typeof(ClassB);
var bClass = (ClassB)Activator.CreateInstance(bType);
En otras palabras, ClassB
no se puede cargar, que es algo que la llamada a GetTypes comprueba y lanza.
Entonces, para calificar de forma segura el conjunto de resultados para los tipos cargables, según este artículo de Phil Haacked Obtener todos los tipos en un ensamblaje y el código Jon Skeet, en su lugar, haría 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);
}
}
}
Y entonces:
private IEnumerable<Type> GetTypesWithInterface(Assembly asm) {
var it = typeof (IMyInterface);
return asm.GetLoadableTypes().Where(it.IsAssignableFrom).ToList();
}