Obtenir tous les types qui mettent en œuvre une interface

en utilisant la réflexion, comment puis-je obtenir tous les types qui mettent en œuvre une interface avec C# 3.0/.NET 3.5 avec le moins de code, et en minimisant les itérations?

C'est ce que je veux réécrire:

foreach (Type t in this.GetType().Assembly.GetTypes())
    if (t is IMyInterface)
        ; //do stuff
456
demandé sur Ondrej Janacek 2008-08-25 23:57:21

12 réponses

Mine serait ceci en c # 3.0 :)

var type = typeof(IMyInterface);
var types = AppDomain.CurrentDomain.GetAssemblies()
    .SelectMany(s => s.GetTypes())
    .Where(p => type.IsAssignableFrom(p));

Fondamentalement, le moins d'itérations sera toujours:

loop assemblies  
 loop types  
  see if implemented.
669
répondu Darren Kopp 2013-09-06 18:41:47

pour trouver tous les types dans un assemblage qui implémente l'interface IFoo:

var results = from type in someAssembly.GetTypes()
              where typeof(IFoo).IsAssignableFrom(type)
              select type;

notez que la suggestion de Ryan Rinaldi était incorrecte. Il retournera 0 types. Vous ne pouvez pas écrire

where type is IFoo

parce que le type est un système.Type instance, et ne sera jamais de type IFoo. Au lieu de cela, vous vérifiez si IFoo est assignable à partir du type. Vous obtiendrez les résultats escomptés.

aussi, la suggestion D'Adam Wright, qui est actuellement marqué comme réponse, la réponse est incorrecte, et pour la même raison. À l'exécution, vous verrez 0 types revenir, parce que tout le système.Les instances de Type N'étaient pas IFoo implementors.

53
répondu Judah Himango 2008-08-25 20:44:18

ça a marché pour moi. Il boucle à travers les classes et vérifie pour voir si elles sont dérivées de myInterface

 foreach (Type mytype in System.Reflection.Assembly.GetExecutingAssembly().GetTypes()
                 .Where(mytype => mytype .GetInterfaces().Contains(typeof(myInterface)))) {
    //do stuff
 }
48
répondu Ben Watkins 2017-08-11 15:06:02

je comprends que c'est une question très ancienne, mais j'ai pensé que je voudrais ajouter une autre réponse pour les futurs utilisateurs que toutes les réponses à ce jour utilisent une certaine forme de Assembly.GetTypes .

alors que GetTypes () retournera effectivement tous les types, cela ne signifie pas nécessairement que vous pourriez les activer et donc potentiellement jeter un ReflectionTypeLoadException .

Un exemple classique pour ne pas être en mesure d'activer un type de serait lorsque le type retourné est derived de base mais base est défini dans un assemblage différent de celui de derived , un assemblage auquel l'ensemble appelant ne fait pas référence.

Alors disons que nous avons:

Class A // in AssemblyA
Class B : Class A, IMyInterface // in AssemblyB
Class C // in AssemblyC which references AssemblyB but not AssemblyA

Si ClassC qui est dans AssemblyC nous de faire quelque chose comme par accepté de répondre:

var type = typeof(IMyInterface);
var types = AppDomain.CurrentDomain.GetAssemblies()
    .SelectMany(s => s.GetTypes())
    .Where(p => type.IsAssignableFrom(p));

alors il lancera un ReflectionTypeLoadException .

c'est parce que sans une référence à AssemblyA dans AssemblyC vous ne seriez pas en mesure de:

var bType = typeof(ClassB);
var bClass = (ClassB)Activator.CreateInstance(bType);

en d'autres termes ClassB n'est pas chargeable ce qui est quelque chose que l'appel à GetTypes vérifie et lance.

ainsi pour qualifier en toute sécurité l'ensemble de résultats pour les types chargeables puis selon ce Phil Haacked article obtenir tous les Types dans un Assemblée et Jon Skeet code vous serait plutôt de faire quelque chose comme:

public static class TypeLoaderExtensions {
    public static IEnumerable<Type> GetLoadableTypes(this Assembly assembly) {
        if (assembly == null) throw new ArgumentNullException("assembly");
        try {
            return assembly.GetTypes();
        } catch (ReflectionTypeLoadException e) {
            return e.Types.Where(t => t != null);
        }
    }
}

et puis:

private IEnumerable<Type> GetTypesWithInterface(Assembly asm) {
    var it = typeof (IMyInterface);
    return asm.GetLoadableTypes().Where(it.IsAssignableFrom).ToList();
}
42
répondu rism 2017-05-23 11:54:59

autres réponses utilisez ici IsAssignableFrom . Vous pouvez également utiliser FindInterfaces de l'espace de noms System , comme décrit ici .

voici un exemple qui vérifie tous les assemblages dans le dossier de l'assemblage en cours d'exécution, à la recherche de classes qui implémentent une certaine interface (en évitant LINQ pour plus de clarté).

static void Main() {
    const string qualifiedInterfaceName = "Interfaces.IMyInterface";
    var interfaceFilter = new TypeFilter(InterfaceFilter);
    var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
    var di = new DirectoryInfo(path);
    foreach (var file in di.GetFiles("*.dll")) {
        try {
            var nextAssembly = Assembly.ReflectionOnlyLoadFrom(file.FullName);
            foreach (var type in nextAssembly.GetTypes()) {
                var myInterfaces = type.FindInterfaces(interfaceFilter, qualifiedInterfaceName);
                if (myInterfaces.Length > 0) {
                    // This class implements the interface
                }
            }
        } catch (BadImageFormatException) {
            // Not a .net assembly  - ignore
        }
    }
}

public static bool InterfaceFilter(Type typeObj, Object criteriaObj) {
    return typeObj.ToString() == criteriaObj.ToString();
}

, Vous pouvez définir une liste d'interfaces si vous voulez correspondre à plus d'un.

18
répondu hillstuk 2017-06-07 12:19:49

boucle à travers tous les assemblages chargés, boucle à travers tous leurs types, et de vérifier s'ils mettent en œuvre l'interface.

quelque chose comme:

Type ti = typeof(IYourInterface);
foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) {
    foreach (Type t in asm.GetTypes()) {
        if (ti.IsAssignableFrom(t)) {
            // here's your type in t
        }
    }
}
13
répondu Lasse Vågsæther Karlsen 2017-04-28 12:40:06

cela a fonctionné pour moi (si vous le souhaitez, vous pouvez exclure les types de systèmes dans la recherche):

Type lookupType = typeof (IMenuItem);
IEnumerable<Type> lookupTypes = GetType().Assembly.GetTypes().Where(
        t => lookupType.IsAssignableFrom(t) && !t.IsInterface); 
7
répondu Carl Nayak 2011-06-29 09:55:20

Edit: je viens de voir l'edit pour clarifier que la question originale était pour la réduction des itérations / code et c'est tout bien et bon comme un exercice, mais dans des situations réelles, vous allez vouloir l'implémentation la plus rapide, indépendamment de la façon dont cool le LINQ sous-jacent semble.

voici ma méthode Utils pour itérer à travers les types chargés. Il gère les classes régulières ainsi que les interfaces, et l'option exclusidesystemtypes accélère considérablement les choses si vous êtes à la recherche d'implémentations dans votre propre / base de codes tiers.

public static List<Type> GetSubclassesOf(this Type type, bool excludeSystemTypes) {
    List<Type> list = new List<Type>();
    IEnumerator enumerator = Thread.GetDomain().GetAssemblies().GetEnumerator();
    while (enumerator.MoveNext()) {
        try {
            Type[] types = ((Assembly) enumerator.Current).GetTypes();
            if (!excludeSystemTypes || (excludeSystemTypes && !((Assembly) enumerator.Current).FullName.StartsWith("System."))) {
                IEnumerator enumerator2 = types.GetEnumerator();
                while (enumerator2.MoveNext()) {
                    Type current = (Type) enumerator2.Current;
                    if (type.IsInterface) {
                        if (current.GetInterface(type.FullName) != null) {
                            list.Add(current);
                        }
                    } else if (current.IsSubclassOf(type)) {
                        list.Add(current);
                    }
                }
            }
        } catch {
        }
    }
    return list;
}

ce n'est pas joli, je l'admets.

5
répondu tags2k 2017-04-28 12:40:53

il n'y a pas de moyen facile (en termes de performance) de faire ce que vous voulez faire.

réflexion fonctionne avec des assemblages et des types principalement de sorte que vous aurez à obtenir tous les types de l'assemblage et de les interroger pour la bonne interface. Voici un exemple:

Assembly asm = Assembly.Load("MyAssembly");
Type[] types = asm.GetTypes();
Type[] result = types.where(x => x.GetInterface("IMyInterface") != null);

qui vous fournira tous les types qui mettent en œuvre L'IMyInterface dans L'assemblage MyAssembly

2
répondu Jorge Córdoba 2008-08-25 20:13:17

j'ai eu des exceptions dans le code linq donc je le fais de cette façon (sans extension compliquée):

private static IList<Type> loadAllTypes(Types[] interfaces)
{
    IList<Type> objects = new List<Type>();

    // find all types
    foreach (var interfaceType in interfaces)
        foreach (var currentAsm in AppDomain.CurrentDomain.GetAssemblies())
            try
            {
                foreach (var currentType in currentAsm.GetTypes())
                    if (interfaceType.IsAssignableFrom(currentType) && currentType.IsClass && !currentType.IsAbstract)
                        objects.Add(currentType);
            }
            catch { }

    return objects;
}
0
répondu user6537157 2018-02-27 10:47:08

autre réponse ne fonctionnait pas avec une interface générique .

celui-ci ne, il suffit de remplacer typeof(ISomeInterface) par typeof (T).

List<string> types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes())
            .Where(x => typeof(ISomeInterface).IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract)
            .Select(x => x.Name).ToList();

ainsi que

AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes())

nous obtenons tous les assemblages

!x.IsInterface && !x.IsAbstract

est utilisé pour exclure l'interface et abstraits et

.Select(x => x.Name).ToList();

de les avoir dans une liste.

0
répondu 421 2018-09-20 08:27:36

, Vous pouvez utiliser certains de LINQ pour obtenir la liste:

var types = from type in this.GetType().Assembly.GetTypes()
            where type is ISomeInterface
            select type;

mais est-ce plus lisible?

-3
répondu Ryan Rinaldi 2008-08-25 20:18:59