2010-05-05 3 views
4

Je souhaite rechercher dans toutes les classes d'un espace de noms pour celles contenant une certaine méthode. Si une classe contient une méthode, je veux créer une instance de la classe et exécuter la méthode.Recherche de toutes les classes contenant une méthode en C#

Évidemment, je dois commencer par la réflexion, mais je suis coincé sur où aller.

Edit:

interfaces ne sont pas la façon dont je veux faire.

Ce que je recherche est l'intégration de fonctions de test dans le code, mais une seule interface d'appel. S'il y a une fonction d'autotest, appelez-la. Si ce n'est pas le cas, ignorez-le.

+0

Dupliquer? http://stackoverflow.com/questions/919826/invoke-method-by-methodinfo –

+0

Cela semble vraiment dangereux. Pouvez-vous marquer toutes les classes avec un attribut ou une interface? –

+1

Ceci est une question de conception mais je pense qu'il est logique que les gens aient un peu plus de contexte dans ce cas. Pouvez-vous monter d'un niveau et exprimer votre intention? –

Répondre

10

Sans plus d'informations sur ce qui distingue la méthode, je vais juste l'assumer est distingué par le nom, et il est public. L'hypothèse de nom est dangereuse, donc je ne recommanderais pas cela, mais ce qui suit devrait faire ce que vous voulez (en supposant que Activator est capable de créer une instance).

EDIT: Ajout de Where(x => x.Namespace == "My.Name.Space") pour limiter les résultats à un seul espace de noms cible.

EDIT: Ajout de if ... else pour gérer le cas des méthodes statiques.

var methods = AppDomain.CurrentDomain.GetAssemblies() 
    .Select(x => x.GetTypes()) 
    .SelectMany(x => x) 
    .Where(x => x.Namespace == "My.Name.Space") 
    .Where(c => c.GetMethod("MethodName") != null) 
    .Select(c => c.GetMethod("MethodName")); 

foreach (MethodInfo mi in methods) 
{ 
    if (mi.IsStatic) 
    { 
     mi.Invoke(null, null); // replace null with the appropriate arguments 
    } 
    else if (!mi.DeclaringType.IsAbstract) 
    { 
     var obj = Activator.CreateInstance(mi.DeclaringType); 
     mi.Invoke(obj, null); // replace null with the appropriate arguments 
    } 
} 

Si vous avez le contrôle sur les types, cependant, la suggestion de jrummel sur les interfaces est un moyen beaucoup plus sûr de le faire.

+0

+1 pour linq avec reflet - sympa! –

+0

Très proche - je ne voudrais que rechercher mon espace de noms, cependant. –

+0

@ Loren Mes excuses - solution facile. – Dathan

11

Créez une interface qui déclare la méthode, puis implémentez différentes classes dans cette interface.

Vous pouvez ensuite utiliser la réflexion à find all types within an assembly that implement that interface. À partir de là, vous devrez créer une instance de chaque type, puis appeler la méthode. Les détails de mise en œuvre varient en fonction de ce que vous essayez de faire.

mise à jour en fonction des commentaires:

Je pense encore une interface (ou attribut) est le chemin à parcourir. C'est comme ça que ça fonctionnerait avec une interface.

interface ISelfTester 
{ 
    void SelfTest(); 
} 

class SomeClass : ISelfTester 
{ 
    /* ... */ 

    public void SelfTest() 
    { 
     // test code 
    } 

    /* ... */ 
} 

Vous pouvez ensuite invoquer la méthode SelfTest de chaque type comme si (emprunt de Dathan et Darren Kopp):

var type = typeof(ISelfTester); 
var types = AppDomain.CurrentDomain.GetAssemblies() 
    .Select(x => x.GetTypes()) 
    .SelectMany(x => x) 
    .Where(x => x.Namespace == "My.Name.Space" && type.IsAssignableFrom(x)); 

foreach (Type t in types) 
{ 
    ISelfTester obj = Activator.CreateInstance(t) as ISelfTester; 
    obj.SelfTest(); 
} 
+1

+5, s'il était possible de vous donner +5. Je vais devoir me contenter de +1 –

2

Une option serait d'utiliser Reflection, comme décrit ci-dessus, mais plutôt que de trouver la méthode par son nom, recherchez une méthode étiquetée avec un attribut personnalisé approprié. Ceci est similaire à ce que fait le MS DataContractSerializer avec des attributs comme [OnDeserializing]. De cette façon, l'implémenteur de classe explique spécifiquement son intention pour la méthode, plutôt que de la faire soudainement faire quelque chose d'inattendu à cause de son nom particulier. Sur une note de côté, puisque ce que vous cherchez est une méthode de test, vous pouvez vérifier quelque chose comme NUnit. Il existe plusieurs excellents cadres de tests unitaires gratuits. Ils fournissent également des fonctionnalités supplémentaires qui peuvent vous aider dans vos tests, car ils fournissent l'échafaudage pour les différents types d'assertions de test que vous pourriez vouloir faire.

+0

Ce que je cherchais, c'est simplement d'inclure une méthode SelfTest() dans n'importe quelle classe ayant des capacités de test. Cela met le code de test à droite avec le code qu'il teste. Cependant, je ne veux pas avoir à maintenir une liste de ces méthodes pour appeler, mais plutôt les trouver. Le compilateur peut certainement le faire et le faire manuellement risque le bug de ne pas en ajouter un à la liste. –

+1

@Loren utilisant un attribut personnalisé pour ce faire est probablement beaucoup plus sûr. En utilisant l'attribut personnalisé, vous permettez à la classe d'implémentation de nommer la méthode comme bon lui semble et de la marquer avec l'attribut approprié. Ensuite, vous pouvez utiliser la réflexion pour rechercher toutes les méthodes qui ont cet attribut et appeler ces méthodes. De cette façon, vous n'êtes pas tributaire de la classe appelante nommant la méthode correctement et vous n'avez aucun problème si quelqu'un arrive à nommer la mauvaise méthode. – Stephan

Questions connexes