Obtener todos los tipos que implementan una interfaz

Usando la reflexión, ¿cómo puedo obtener todos los tipos que implementan una interfaz con C # 3.0 / .NET 3.5 con el menor código y minimizando las iteraciones?

Esto es lo que quiero volver a escribir:

foreach (Type t in this.GetType().Assembly.GetTypes()) if (t is IMyInterface) ; //do stuff 

El mío sería este en c # 3.0 🙂

 var type = typeof(IMyInterface); var types = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(s => s.GetTypes()) .Where(p => type.IsAssignableFrom(p)); 

Básicamente, la menor cantidad de iteraciones siempre será:

 loop assemblies loop types see if implemented. 

Para buscar todos los tipos en un ensamblado que implemente la interfaz IFoo:

 var results = from type in someAssembly.GetTypes() where typeof(IFoo).IsAssignableFrom(type) select type; 

Tenga en cuenta que la sugerencia de Ryan Rinaldi fue incorrecta. Devolverá 0 tipos. No puedes escribir

 where type is IFoo 

porque type es una instancia de System.Type y nunca será de tipo IFoo. En cambio, verifica si IFoo es asignable del tipo. Eso obtendrá los resultados esperados.

Además, la sugerencia de Adam Wright, que actualmente está marcada como la respuesta, también es incorrecta y por el mismo motivo. En el tiempo de ejecución, verá que regresan 0 tipos, porque todas las instancias System.Type no fueron implementadores IFoo.

Esto funcionó para mí. Sin embargo, recorre las clases y comprueba si se derivan de myInterface

  foreach (Type mytype in System.Reflection.Assembly.GetExecutingAssembly().GetTypes() .Where(mytype => mytype .GetInterfaces().Contains(typeof(myInterface)))) { //do stuff } 

Agradezco que esta sea 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 () devolverá todos los tipos, no significa necesariamente que pueda activarlos y, por lo tanto, podría arrojar una ReflectionTypeLoadException .

Un ejemplo clásico para no poder activar un tipo sería cuando el tipo devuelto se derived de la base pero la base se define en un ensamblaje diferente del derived , un ensamblaje al que el ensamblado llamante 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 que está en AssemblyC , 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)); 

Luego arrojará una ReflectionTypeLoadException .

Esto se debe a que sin una referencia a AssemblyA en AssemblyC usted no podría:

 var bType = typeof(ClassB); var bClass = (ClassB)Activator.CreateInstance(bType); 

En otras palabras, ClassB no es cargable, lo cual es algo que la llamada a GetTypes verifica 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 código de ensamblaje y Jon Skeet, en su lugar harías algo como:

 public static class TypeLoaderExtensions { public static IEnumerable 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 GetTypesWithInterface(Assembly asm) { var it = typeof (IMyInterface); return asm.GetLoadableTypes().Where(it.IsAssignableFrom).ToList(); } 

Otras respuestas aquí usan IsAssignableFrom . También puede usar FindInterfaces desde el espacio de nombres del System , como se describe aquí .

Aquí hay un ejemplo que verifica todos los ensamblajes en la carpeta del ensamblaje que se está ejecutando actualmente, buscando clases que implementen una cierta interfaz (evitando LINQ para mayor claridad).

 static void Main() { const string qualifiedInterfaceName = "Interfaces.IMyInterface"; var interfaceFilter = new TypeFilter(InterfaceFilter); var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); var di = new DirectoryInfo(path); foreach (var file in di.GetFiles("*.dll")) { try { var nextAssembly = Assembly.ReflectionOnlyLoadFrom(file.FullName); foreach (var type in nextAssembly.GetTypes()) { var myInterfaces = type.FindInterfaces(interfaceFilter, qualifiedInterfaceName); if (myInterfaces.Length > 0) { // This class implements the interface } } } catch (BadImageFormatException) { // Not a .net assembly - ignore } } } public static bool InterfaceFilter(Type typeObj, Object criteriaObj) { return typeObj.ToString() == criteriaObj.ToString(); } 

Puede configurar una lista de interfaces si quiere hacer coincidir más de una.

recorra todos los ensamblados cargados, recorra todos sus tipos y verifique si implementan la interfaz.

algo como:

 Type ti = typeof(IYourInterface); foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) { foreach (Type t in asm.GetTypes()) { if (ti.IsAssignableFrom(t)) { // here's your type in t } } } 

Esto funcionó para mí (si lo desea, podría excluir los tipos de sistema en la búsqueda):

 Type lookupType = typeof (IMenuItem); IEnumerable lookupTypes = GetType().Assembly.GetTypes().Where( t => lookupType.IsAssignableFrom(t) && !t.IsInterface); 

Editar: Acabo de ver la edición para aclarar que la pregunta original era para la reducción de iteraciones / código y eso está muy bien como ejercicio, pero en situaciones del mundo real vas a querer la implementación más rápida, independientemente de lo genial que se ve el LINQ subyacente.

Aquí está mi método Utils para iterar a través de los tipos cargados. Maneja clases regulares así como interfaces, y la opción excludeSystemTypes acelera enormemente las cosas si está buscando implementaciones en su propia base de código / de terceros.

 public static List GetSubclassesOf(this Type type, bool excludeSystemTypes) { List list = new List(); IEnumerator enumerator = Thread.GetDomain().GetAssemblies().GetEnumerator(); while (enumerator.MoveNext()) { try { Type[] types = ((Assembly) enumerator.Current).GetTypes(); if (!excludeSystemTypes || (excludeSystemTypes && !((Assembly) enumerator.Current).FullName.StartsWith("System."))) { IEnumerator enumerator2 = types.GetEnumerator(); while (enumerator2.MoveNext()) { Type current = (Type) enumerator2.Current; if (type.IsInterface) { if (current.GetInterface(type.FullName) != null) { list.Add(current); } } else if (current.IsSubclassOf(type)) { list.Add(current); } } } } catch { } } return list; } 

No es bonito, lo admito.

No hay una manera fácil (en términos de rendimiento) de hacer lo que quiere hacer.

La reflexión funciona principalmente con ensamblajes y tipos, por lo que deberá obtener todos los tipos de ensamblaje y consultarlos para la interfaz correcta. Aquí hay un ejemplo:

 Assembly asm = Assembly.Load("MyAssembly"); Type[] types = asm.GetTypes(); Type[] result = types.where(x => x.GetInterface("IMyInterface") != null); 

Eso te dará todos los tipos que implementan IMyInterface en la Asamblea MyAssembly

Recibí excepciones en el código linq así que lo hago de esta manera (sin una extensión complicada):

 private static IList loadAllTypes(Types[] interfaces) { IList objects = new List(); // find all types foreach (var interfaceType in interfaces) foreach (var currentAsm in AppDomain.CurrentDomain.GetAssemblies()) try { foreach (var currentType in currentAsm.GetTypes()) if (interfaceType.IsAssignableFrom(currentType) && currentType.IsClass && !currentType.IsAbstract) objects.Add(currentType); } catch { } return objects; } 

Puede usar algunos LINQ para obtener la lista:

 var types = from type in this.GetType().Assembly.GetTypes() where type is ISomeInterface select type; 

Pero realmente, ¿es eso más legible?