Obtener todos los tipos derivados de un tipo

¿Existe alguna forma mejor (más eficiente o más agradable) de encontrar todos los tipos derivados de un tipo? Actualmente estoy usando algo como:

  1. obtener todos los tipos en ensambles usados
  2. revisa mi tipo con todos esos tipos si es ‘IsAssignable’

Me preguntaba si hay una manera mejor de hacer esto.

Una vez usé este método Linq para obtener todos los tipos que heredan de un tipo base B:

var listOfBs = (from domainAssembly in AppDomain.CurrentDomain.GetAssemblies() from assemblyType in domainAssembly.GetTypes() where typeof(B).IsAssignableFrom(assemblyType) select assemblyType).ToArray(); 

EDITAR : Como esto parece tener más repeticiones (por lo tanto, más vistas), permítanme agregar algunos detalles más:

  • Como dice el enlace mencionado anteriormente, este método usa Reflection en cada llamada. Entonces, cuando se usa el método repetidamente para el mismo tipo, uno probablemente podría hacerlo mucho más eficiente cargándolo una vez.
  • Como sugiere Anton , tal vez podría (micro) optimizarlo usando domainAssembly.GetExportedTypes() para recuperar solo los tipos visibles públicamente (si eso es todo lo que necesita).
  • Como menciona Noldorin , Type.IsAssignable también obtendrá el tipo original (no derivado). ( Type.IsSubclassOf no lo hará, pero Type.IsSubclassOf no funcionará si el tipo de base es una interfaz).
  • Uno puede querer / necesitar verificar una clase ‘real’: && ! assemblyType.IsAbstract && ! assemblyType.IsAbstract . (Tenga en cuenta que todas las interfaces se consideran abstractas, consulte MSDN ).

Estoy bastante seguro de que el método que sugirió va a ser la manera más fácil de encontrar todos los tipos derivados. Las clases para padres no almacenan ninguna información sobre cuáles son sus subclases (sería una tontería si lo hicieran), lo que significa que no se puede evitar una búsqueda entre todos los tipos aquí.

La única recomendación es utilizar el método Type.IsAssignable en lugar de Type.IsAssignable para verificar si un tipo particular se deriva de otro. Aún así, tal vez haya una razón por la que necesita usar Type.IsAssignable (funciona con interfaces, por ejemplo).

La única optimización que puede extraer de esto es usar Assembly.GetExportedTypes() para recuperar solo los tipos visibles públicamente si ese es el caso. Aparte de eso, no hay forma de acelerar las cosas. LINQ puede ayudar con el lado de legibilidad de las cosas, pero no con respecto al rendimiento.

Puede hacer un cortocircuito para evitar llamadas innecesarias a IsAssignableFrom que, según Reflector, es bastante caro, al probar primero si el tipo en cuestión es de “clase” requerida. Es decir, si solo está buscando clases, no tiene sentido probar enumeraciones o arreglos para “asignabilidad”.

Creo que no hay una forma mejor ni directa.

Mejor: use IsSubclassOf lugar de IsAssignable .

Asumiendo baseType contiene un objeto System.Type con el que desea verificar y matchType contiene un objeto System.Type con el tipo de su iteración actual (a través de un foreach-loop o lo que sea):

Si desea verificar si matchType se deriva de la clase representada por baseType, usaría

 matchType.IsSubclassOf(baseType) 

Y si quieres verificar si matchType implementa la interfaz representada por baseType, yo usaría

 matchType.GetInterface(baseType.ToString(), false) != null 

Por supuesto, almacenaría baseType.ToString () como una variable global, así que no necesitaría llamarlo todo el tiempo. Y como probablemente lo necesite en un contexto en el que tenga muchos tipos, también podría considerar usar System.Threading.Tasks.Parallel.ForEach-Loop para recorrer todos sus tipos …

Si solo estás interesado en explorar, entonces .NET Reflector tiene la capacidad de hacer esto. Sin embargo, no es algo que sea realmente factible. ¿Te gustaría que todos los tipos que están en los ensamblados actualmente cargados? Asambleas a las que hace referencia la asamblea ejecutora Hay muchas formas diferentes de obtener una lista de tipos, y escribir algo que justifique (y brinde opciones) sería un costo bastante grande con un beneficio relativamente bajo.

¿Que estás tratando de hacer? Es probable que haya una forma mejor (o al menos más eficiente) de lograrlo.