2009-05-13 7 views
47

Existe-t-il un meilleur moyen (plus performant ou plus agréable) de trouver tous les types dérivés d'un type? Actuellement im en utilisant quelque chose comme:Obtenir tous les types dérivés d'un type

  1. obtenir tous types dans les assemblages utilisés
  2. vérifier mon type avec tous ces types si elle est « IsAssignable »

je me demandais s'il y a une meilleure todo façon ce?

+0

En quoi est-ce étrange? Ce n'est pas quelque chose qui est souvent nécessaire. –

+0

Je pensais juste que c'était un lourd coût de performance, pour "juste savoir quels types sont dérivés d'un certain type" (je vais couper le 'étrange';) – Bluenuance

+0

Avez-vous regardé en utilisant [Enumerable.OfType] (http: // msdn .microsoft.com/fr-us/library/bb360913.aspx)? –

Répondre

7

La seule optimisation que vous pouvez en extraire est d'utiliser Assembly.GetExportedTypes() pour récupérer uniquement les types visibles publiquement si c'est le cas. À part ça, il n'y a aucun moyen d'accélérer les choses. LINQ peut aider avec la lisibilité des choses, mais pas sur le plan de la performance.

Vous pouvez faire un peu de court-circuit pour éviter les appels inutiles à IsAssignableFrom qui est, selon Reflector, assez cher, en testant d'abord si le type en question est de la "classe" requise. C'est-à-dire que vous recherchez uniquement des classes, il est inutile de tester des énumérations ou des tableaux pour déterminer leur "assignabilité".

10

Je suis assez sûr que la méthode que vous avez suggérée sera la façon la plus facile de trouver tous les types dérivés. Les classes parentes ne stockent aucune information sur ce que sont leurs sous-classes (ce serait bête si elles l'ont fait), ce qui signifie qu'il est impossible d'éviter une recherche parmi tous les types ici. Il est seulement recommandé d'utiliser la méthode Type.IsSubclassOf au lieu de Type.IsAssignable afin de vérifier si un type particulier est dérivé d'un autre. Pourtant, peut-être il y a une raison pour laquelle vous devez utiliser Type.IsAssignable (cela fonctionne avec des interfaces, par exemple).

+3

Remarque: IsSubclassOf ne fonctionne pas si la "classe de base" est en fait une interface, contrairement à IsAssignableFrom. –

+0

@Stefan: Oui, je l'ai mentionné dans Ma réponse dépend du contexte exact, que le demandeur veut utiliser – Noldorin

1

Si vous êtes uniquement intéressé par la navigation, alors .NET Reflector a la capacité de le faire. Cependant, ce n'est pas quelque chose de vraiment réalisable. Souhaitez-vous tous les types figurant dans les assemblys actuellement chargés? Assemblages référencés par l'assembly d'exécution? Il y a plusieurs façons d'obtenir une liste de Types, et écrire quelque chose qui rendrait compte (et fournir des options) serait un coût assez important avec des bénéfices relativement faibles.

Qu'essayez-vous de faire? Il y a probablement une meilleure façon (ou au moins plus efficace) de l'accomplir.

4

Je pense qu'il n'y a pas de meilleure ou de plus directe.

Mieux: Utilisez IsSubclassOf au lieu de IsAssignable.

+2

Qu'est-ce qui vous fait dire que IsSubclassOf est "meilleur"? Il ne fonctionne pas avec les interfaces, et je ne vois aucun avantage immédiat ... –

+12

Sous-classe _implies_ sous-typage Sous-typage _implies_ assignabilité Par exemple, I et I n'ont pas de relation de sous-classe ou de sous-type, mais l'une est affectable à l'autre si I est covariant ou contravariant dans T. Quand on considère la question du sous-typage, IsSubClassOf n'a pas de faux positifs mais a des faux négatifs et IsAssignable n'a pas de faux négatifs mais a des faux positifs. Il est clair que ni l'un ni l'autre n'est correct, de sorte que "mieux" est un appel au jugement; Préférez-vous les faux négatifs ou les faux positifs? –

4

Asuming baseType contient un objet System.Type que vous voulez vérifier et contre matchType contient un objet System.Type avec le type de votre itération courante (à travers une boucle foreach ou autre):

Si vous voulez pour vérifier wheather matchType est dérivé de la classe représentée par baseType j'utiliser

matchType.IsSubclassOf(baseType) 

Et si vous voulez vérifier wheather matchType implémente l'interface représentée par baseType j'utiliser

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

Bien sûr, je stockerais baseType.ToString() comme une variable globale, donc je n'aurais pas besoin de l'appeler tout le temps. Et puisque vous en auriez probablement besoin dans un contexte où vous avez beaucoup de types, vous pourriez aussi envisager d'utiliser System.Threading.Tasks.Parallel.ForEach-boucle pour itérer tous vos types ...

44

Je once utilisé cette LINQ méthode pour obtenir tous les types héritant d'un type de base B:

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

EDIT: Comme cela semble encore Pour obtenir plus de rep (donc plus de vues), laissez-moi ajouter quelques détails:

  • Comme les états de lien mentionnés ci-dessus, cette méthode utilise la réflexion à chaque appel. Donc, lorsque vous utilisez la méthode à plusieurs reprises pour le même type, on pourrait probablement le rendre beaucoup plus efficace en le chargeant une fois.
  • Comme le suggère Anton, vous pourriez peut-être (micro) l'optimiser en utilisant domainAssembly.GetExportedTypes() pour récupérer uniquement les types visibles publiquement (si c'est tout ce dont vous avez besoin).
  • Comme Noldorin mentions, Type.IsAssignable obtiendra également le type d'origine (non dérivé). (Type.IsSubclassOf ne sera pas, mais Type.IsSubclassOf ne fonctionnera pas si le type de base est une interface).
  • On peut vouloir/besoin de vérifier une «vraie» classe: && ! assemblyType.IsAbstract. (Notez que toutes les interfaces sont considérées comme abstraites, voir MSDN.)
Questions connexes