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?
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.
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.
Un exemple utilisant Linq:
var types =
myAssembly.GetTypes()
.Where(m => m.IsClass && m.GetInterface("IMyInterface") != null);
foreach (Type t in Assembly.GetCallingAssembly().GetTypes())
{
if (t.GetInterface("ITheInterface") != null)
{
ITheInterface executor = Activator.CreateInstance(t) as ITheInterface;
executor.PerformSomething();
}
}
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.
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();