2011-01-14 7 views
47

Je dois rechercher des types spécifiques dans tous les assemblages d'un site Web ou d'une application Windows. Existe-t-il un moyen simple de procéder? Comme la façon dont la fabrique de contrôleurs pour ASP.NET MVC regarde tous les assemblages pour les contrôleurs.Rechercher des types dans tous les assemblages

Merci.

Répondre

79

Il y a deux étapes pour y parvenir:

  • Le AppDomain.CurrentDomain.GetAssemblies() vous donne toutes les assemblées chargées dans le domaine d'application actuel.
  • La classe Assembly fournit une méthode GetTypes() pour récupérer tous les types dans cet assembly particulier.

D'où votre code pourrait ressembler à ceci:

foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies()) 
{ 
    foreach (Type t in a.GetTypes()) 
    { 
     // ... do something with 't' ... 
    } 
} 

Pour rechercher des types spécifiques (par exemple, la mise en œuvre d'une interface donnée, héritant d'un ancêtre commun ou autre), vous devrez filtrer-la résultats. Dans le cas où vous auriez besoin de le faire à plusieurs endroits dans votre application, c'est une bonne idée de créer une classe d'aide offrant différentes options. Par exemple, j'ai souvent appliqué des filtres de préfixe d'espace de noms, des filtres d'implémentation d'interface et des filtres d'héritage. Pour une documentation détaillée, consultez MSDN here et here.

+0

Bien sûr, si vous alliez faire un filtrage sur ces types et assemblages, vous utiliseriez LINQ, n'est-ce pas? ;) –

+6

@Niall Connaughton C'est une question de préférence personnelle. –

+2

J'ai trouvé des situations où cela provoquait une exception, parce que mon application générait des assemblages dynamiques, juste un gotcha à connaître. Vous pouvez identifier les assemblages dynamiques et les ignorer comme ceci http://stackoverflow.com/questions/1423733/how-to-tell-if-a-net-assembly-is-dynamic - si cela pose un problème –

26

Facile LINQ:

IEnumerable<Type> types = 
      from a in AppDomain.CurrentDomain.GetAssemblies() 
      from t in a.GetTypes() 
      select t; 

foreach(Type t in types) 
{ 
    ... 
} 
19

solution LINQ avec vérification pour voir si l'ensemble est dynamique:

/// <summary> 
/// Looks in all loaded assemblies for the given type. 
/// </summary> 
/// <param name="fullName"> 
/// The full name of the type. 
/// </param> 
/// <returns> 
/// The <see cref="Type"/> found; null if not found. 
/// </returns> 
private static Type FindType(string fullName) 
{ 
    return 
     AppDomain.CurrentDomain.GetAssemblies() 
      .Where(a => !a.IsDynamic) 
      .SelectMany(a => a.GetTypes()) 
      .FirstOrDefault(t => t.FullName.Equals(fullName)); 
} 
4

Le plus souvent vous n'êtes intéressé que par les assemblées qui sont visibles de l'extérieur . Pour cela, vous devez appeler GetExportedTypes() Mais à part cela, une ReflectionTypeLoadException peut être levée. Le code suivant prend soin de ces situations.

public static IEnumerable<Type> FindTypes(Func<Type, bool> predicate) 
{ 
    if (predicate == null) 
     throw new ArgumentNullException(nameof(predicate)); 

    foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) 
    { 
     if (!assembly.IsDynamic) 
     { 
      Type[] exportedTypes = null; 
      try 
      { 
       exportedTypes = assembly.GetExportedTypes(); 
      } 
      catch (ReflectionTypeLoadException e) 
      { 
       exportedTypes = e.Types; 
      } 

      if (exportedTypes != null) 
      { 
       foreach (var type in exportedTypes) 
       { 
        if (predicate(type)) 
         yield return type; 
       } 
      } 
     } 
    } 
} 
Questions connexes