Question basée sur l' exemple MSDN .
Disons que nous avons des classes C # avec HelpAttribute dans une application de bureau autonome. Est-il possible d'énumérer toutes les classes avec un tel attribut? Est-il judicieux de reconnaître les classes de cette façon? L'attribut personnalisé serait utilisé pour lister les options de menu possibles, la sélection d'un élément amènera à l'écran l'instance de cette classe. Le nombre de classes / éléments augmentera lentement, mais de cette façon, nous pouvons éviter de les énumérer tous ailleurs, je pense.
Select
méthode d'extension, et le compilateur générera une machine à états comme il le ferait si vous appeliez àSelect
cause de votre utilisation deyield return
. Enfin, les gains de performances qui pourraient être obtenus dans la majorité des cas sont des micro-optimisations.Eh bien, vous devrez énumérer toutes les classes de tous les assemblys chargés dans le domaine d'application actuel. Pour ce faire, vous appelleriez la
GetAssemblies
méthode sur l'AppDomain
instance pour le domaine d'application actuel.À partir de là, vous appelleriez
GetExportedTypes
(si vous ne voulez que des types publics) ouGetTypes
sur chacunAssembly
d' eux pour obtenir les types contenus dans l'assembly.Ensuite, vous appelleriez la
GetCustomAttributes
méthode d'extension sur chaqueType
instance, en passant le type de l'attribut que vous souhaitez trouver.Vous pouvez utiliser LINQ pour simplifier cela pour vous:
La requête ci-dessus vous obtiendra chaque type avec votre attribut appliqué, ainsi que l'instance du ou des attributs qui lui sont attribués.
Notez que si vous avez un grand nombre d'assemblys chargés dans votre domaine d'application, cette opération peut être coûteuse. Vous pouvez utiliser Parallel LINQ pour réduire la durée de l'opération, comme ceci:
Le filtrer sur un spécifique
Assembly
est simple:Et si l'assembly contient un grand nombre de types, vous pouvez à nouveau utiliser Parallel LINQ:
la source
D'autres réponses font référence à GetCustomAttributes . Ajout de celui-ci comme exemple d'utilisation d' IsDefined
la source
Comme déjà indiqué, la réflexion est la voie à suivre. Si vous appelez cela fréquemment, je suggère fortement de mettre en cache les résultats, car la réflexion, en particulier l'énumération de chaque classe, peut être assez lente.
Ceci est un extrait de mon code qui traverse tous les types dans tous les assemblys chargés:
la source
Il s'agit d'une amélioration des performances en plus de la solution acceptée. Itérer toutes les classes peut être lent car il y en a tellement. Parfois, vous pouvez filtrer un assemblage entier sans regarder aucun de ses types.
Par exemple, si vous recherchez un attribut que vous avez déclaré vous-même, vous ne vous attendez pas à ce que l'une des DLL système contienne des types avec cet attribut. La propriété Assembly.GlobalAssemblyCache est un moyen rapide de rechercher les DLL système. Quand j'ai essayé cela sur un vrai programme, j'ai découvert que je pouvais sauter 30 101 types et que je n'avais qu'à vérifier 1 983 types.
Une autre façon de filtrer consiste à utiliser Assembly.ReferencedAssemblies. Vraisemblablement, si vous voulez des classes avec un attribut spécifique et que cet attribut est défini dans un assembly spécifique, vous ne vous souciez que de cet assembly et des autres assemblys qui le référencent. Dans mes tests, cela m'a aidé un peu plus que la vérification de la propriété GlobalAssemblyCache.
J'ai combiné les deux et je l'ai obtenu encore plus rapidement. Le code ci-dessous comprend les deux filtres.
la source
En cas de limitations de Portable .NET , le code suivant devrait fonctionner:
ou pour un grand nombre d'assemblys utilisant des états de boucle
yield return
:la source
Nous pouvons améliorer la réponse d'Andrew et convertir le tout en une seule requête LINQ.
la source