Pregunta basada en el ejemplo de MSDN .
Digamos que tenemos algunas clases de C # con HelpAttribute en una aplicación de escritorio independiente. ¿Es posible enumerar todas las clases con dicho atributo? ¿Tiene sentido reconocer las clases de esta manera? El atributo personalizado se usaría para enumerar las posibles opciones de menú, al seleccionar el elemento se mostrará en la pantalla la instancia de dicha clase. El número de clases / artículos crecerá lentamente, pero de esta manera podemos evitar enumerarlos en otros lugares, creo.
Select
método de extensión, y el compilador generará una máquina de estado tal como lo haría si llamaraSelect
debido a su uso deyield return
. Finalmente, cualquier ganancia de rendimiento que se pueda obtener en la mayoría de los casos sería micro optimizaciones.Bueno, tendría que enumerar todas las clases en todos los ensamblados que se cargan en el dominio de la aplicación actual. Para hacer eso, llamaría al
GetAssemblies
método en laAppDomain
instancia para el dominio de la aplicación actual.Desde allí, llamaría
GetExportedTypes
(si solo desea tipos públicos) oGetTypes
en cada unoAssembly
para obtener los tipos contenidos en el ensamblado.Luego, llamaría al
GetCustomAttributes
método de extensión en cadaType
instancia, pasando el tipo de atributo que desea encontrar.Puede usar LINQ para simplificar esto para usted:
La consulta anterior le proporcionará cada tipo con su atributo aplicado, junto con la instancia de los atributos asignados a él.
Tenga en cuenta que si tiene una gran cantidad de ensamblados cargados en el dominio de su aplicación, esa operación podría ser costosa. Puede usar Parallel LINQ para reducir el tiempo de la operación, así:
Filtrarlo en un específico
Assembly
es simple:Y si el ensamblaje tiene una gran cantidad de tipos, puede usar Parallel LINQ nuevamente:
fuente
Otras respuestas hacen referencia a GetCustomAttributes . Agregar este como ejemplo de uso de IsDefined
fuente
Como ya se dijo, la reflexión es el camino a seguir. Si va a llamar a esto con frecuencia, le recomiendo almacenar en caché los resultados, ya que la reflexión, especialmente la enumeración en cada clase, puede ser bastante lenta.
Este es un fragmento de mi código que se ejecuta en todos los tipos en todos los ensamblados cargados:
fuente
Esta es una mejora del rendimiento además de la solución aceptada. Iterar aunque todas las clases pueden ser lentas porque hay muchas. A veces puede filtrar un conjunto completo sin mirar ninguno de sus tipos.
Por ejemplo, si está buscando un atributo que usted mismo declaró, no espera que ninguna de las DLL del sistema contenga ningún tipo con ese atributo. La propiedad Assembly.GlobalAssemblyCache es una forma rápida de verificar las DLL del sistema. Cuando probé esto en un programa real, descubrí que podía omitir 30,101 tipos y solo tengo que verificar 1,983 tipos.
Otra forma de filtrar es usar Assembly.ReferencedAssemblies. Presumiblemente, si desea clases con un atributo específico, y ese atributo se define en un ensamblaje específico, entonces solo le importa ese ensamblaje y otros ensamblajes que hacen referencia a él. En mis pruebas, esto ayudó un poco más que verificar la propiedad GlobalAssemblyCache.
Combiné ambos y lo obtuve aún más rápido. El siguiente código incluye ambos filtros.
fuente
En el caso de las limitaciones de Portable .NET , el siguiente código debería funcionar:
o para una gran cantidad de ensamblajes que utilizan el estado de bucle
yield return
:fuente
Podemos mejorar la respuesta de Andrew y convertir todo en una consulta LINQ.
fuente