web-dev-qa-db-fra.com

Comment trouver toutes les classes qui implémentent une interface donnée?

Sous un espace de noms donné, j'ai un ensemble de classes qui implémentent une interface. Appelons cela ISomething. J'ai une autre classe (appelons-la CClass) qui connaît ISomething mais ne connaît pas les classes qui implémentent cette interface.

J'aimerais que CClass recherche toute l'implémentation de ISomething, instancie une instance de celle-ci et exécute la méthode.

Quelqu'un at-il une idée sur la façon de faire cela avec C # 3.5?

66
Martin

Un exemple de code de travail:

var instances = from t in Assembly.GetExecutingAssembly().GetTypes()
                where t.GetInterfaces().Contains(typeof(ISomething))
                         && t.GetConstructor(Type.EmptyTypes) != null
                select Activator.CreateInstance(t) as ISomething;

foreach (var instance in instances)
{
    instance.Foo(); // where Foo is a method of ISomething
}

Edit Ajout d'une vérification pour un constructeur sans paramètre afin que l'appel à CreateInstance aboutisse.

129
Matt Hamilton

Vous pouvez obtenir une liste des assemblys chargés en utilisant ceci:

Assembly assembly = System.Reflection.AppDomain.CurrentDomain.GetAssemblies()

À partir de là, vous pouvez obtenir une liste de types dans Assembly (types publics):

Type[] types = Assembly.GetExportedTypes();

Ensuite, vous pouvez demander à chaque type s'il supporte cette interface en trouvant cette interface sur l'objet:

Type interfaceType = type.GetInterface("ISomething");

Je ne sais pas s'il existe un moyen plus efficace de le faire avec réflexion.

10
Mitch Denny

Un exemple utilisant Linq:

var types =
  myAssembly.GetTypes()
            .Where(m => m.IsClass && m.GetInterface("IMyInterface") != null);
8
CMS
foreach (Type t in Assembly.GetCallingAssembly().GetTypes())
{
    if (t.GetInterface("ITheInterface") != null)
    {
        ITheInterface executor = Activator.CreateInstance(t) as ITheInterface;
        executor.PerformSomething();
    }
}
3
Kiran

Vous pouvez utiliser quelque chose comme ce qui suit et l’adapter à vos besoins. 

var _interfaceType = typeof(ISomething);
var currentAssembly = System.Reflection.Assembly.GetExecutingAssembly();
var types = GetType().GetNestedTypes();

foreach (var type in types)
{
    if (_interfaceType.IsAssignableFrom(type) && type.IsPublic && !type.IsInterface)
    {
        ISomething something = (ISomething)currentAssembly.CreateInstance(type.FullName, false);
        something.TheMethod();
    }
}

Ce code pourrait utiliser certaines améliorations de performances, mais c'est un début.

2
Quintin Robinson

Peut-être devrions-nous aller de cette façon

foreach ( var instance in Assembly.GetExecutingAssembly().GetTypes().Where(a => a.GetConstructor(Type.EmptyTypes) != null).Select(Activator.CreateInstance).OfType<ISomething>() ) 
   instance.Execute(); 
0
bane 975