2009-05-13 22 views
47

¿Existe alguna forma mejor (más eficiente o más agradable) de encontrar todos los Tipos derivados de un Tipo? Actualmente Im usar algo como:Obtenga todos los tipos derivados de un tipo

  1. obtener todos los tipos de conjuntos utilizados
  2. comprobar mi tipo con todos esos tipos si es 'IsAssignable'

me preguntaba si tener una mejor manera TODO ¿esta?

+0

¿De qué manera es extraño? No es algo que a menudo se requiere. –

+0

Solo pensé que era un alto costo de rendimiento, por "solo saber qué tipos se derivan de algún tipo '(cortaré el' extraño ';) – Bluenuance

+0

¿Ha mirado usando [Enumerable.OfType] (http: // msdn .microsoft.com/es-us/library/bb360913.aspx)? –

Respuesta

7

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 al 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".

10

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.IsSubclassOf en lugar de Type.IsAssignable para comprobar si un tipo particular se deriva de otro. Aún así, quizás haya una razón por la que necesita usar Type.IsAssignable (funciona con interfaces, por ejemplo).

+3

Nota: IsSubclassOf no funciona si la "clase base" es realmente una interfaz, mientras que IsAssignableFrom si. –

+0

@Stefan: Sí, lo he mencionado en mi respuesta. Todo depende del contexto exacto, que el asker quiera usar. – Noldorin

1

Si solo está interesado en explorar, entonces .NET Reflector tiene la capacidad de hacerlo. 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.

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

4

Creo que no hay una manera mejor ni directa.

Mejor: Use IsSubclassOf en lugar de IsAssignable.

+2

¿Qué te hace decir que IsSubclassOf es "mejor"? No funciona con interfaces, y no puedo ver ningún beneficio inmediato ... –

+12

Subclasificación _implies_ subtipificación Subtipificación _implies_ asignabilidad. Por ejemplo, I y I no tienen relación de subclase o subtipo, pero una se puede asignar a la otra si I es covariante o contravariante en T. Al considerar la cuestión del subtipado, IsSubClassOf no tiene falsos positivos pero tiene falsos negativos e IsAssignable no tiene falsos negativos pero tiene falsos positivos. Claramente ninguno de los dos es correcto, entonces, lo que es "mejor" es una decisión; ¿Prefieres falsos negativos o falsos positivos? –

4

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

Si desea para comprobar tiempo lo matchType se deriva de la clase representada por tipoBase que haría uso de

matchType.IsSubclassOf(baseType) 

Y si desea comprobar matchType tiempo lo implementa la interfaz representada por tipoBase que haría uso de

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

Por supuesto que almacenaría baseType.ToString() como una variable global, así que no tendría que llamarlo todo el tiempo. Y dado que probablemente lo necesite en un contexto en el que tenga muchos tipos, también podría considerar usar System.Threading.Tasks.Parallel.ParaCada-Loop para iterar a través de todos los tipos ...

44

I once utilizaron este LINQ método para obtener todo tipo 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 todavía parece obtener más representantes (por lo tanto, más visitas), permítanme agregar algunos más detalles:

  • Como dice el enlace mencionado anteriormente, este método utiliza 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 Anton sugiere, tal vez podría (micro) optimizarlo usando domainAssembly.GetExportedTypes() para recuperar solo los tipos públicamente visibles (si eso es todo lo que necesita).
  • Como Noldorin menciona, Type.IsAssignable también obtendrá el tipo original (no derivado). (Type.IsSubclassOf no, pero Type.IsSubclassOf no funcionará si el tipo de base es una interfaz).
  • Es posible que desee/necesite verificar una clase 'real': && ! assemblyType.IsAbstract. (Tenga en cuenta que todas las interfaces se consideran abstractas, consulte MSDN.)
Cuestiones relacionadas