2010-12-01 32 views
2

Ce que j'ai, c'est un tas de formulaires dans mon application principale qui ont des fonctions privées et publiques. J'ai une architecture de plugin en place qui accède à chaque formulaire quand il est créé et chargé et contient une référence pour le mettre à jour, ajouter des contrôles, etc.Existe-t-il un moyen d'appeler des fonctions privées d'un formulaire ou d'une classe via Type.InvokeMember ou des messages en C#?

Ce que nous essayons de faire est d'implémenter cette architecture plug-in, mais certains plugins peuvent avoir besoin d'appeler les fonctions privées d'un formulaire. Voici un exemple de ce que j'ai essayé avec Type.InvokeMember:

public partial class Form1 : Form 
{ 
    Form1() 
    { 
     InitializeComponent(); 
    } 

    private void SayHello() 
    { 
     MessageBox.Show("Hello World!"); 
    } 
} 

Dans une autre DLL ...

public class PluginClass 
{ 
    Form1 myReferencedForm1; 

    PluginClass() 
    { 
     //Constructor code here... 

     //Also sets the reference to existing Form1 instance 
    } 

    private CallMember() 
    { 
     Type t = typeof(Form1); //I guess I can also call 'myReferencedForm1.GetType();' here as well 
     t.InvokeMember("SayHello", 
         System.Reflection.BindingFlags.InvokeMethod | 
         System.Reflection.BindingFlags.NonPublic | 
         System.Reflection.BindingFlags.Public, 
         null, myReferencedForm1, new object[] { }); 
    } 
} 

J'ai essayé "SayHello" et "SayHello()" et ils ont tous deux renvoient une erreur 'MissingMethodException':

Method 'Form1.SayHello()' not found. 

Dois-je créer et utiliser un classeur? Si oui, comment je fais ça? Puis-je le faire plus facilement avec un System.Windows.Forms.Message? Si c'est le cas, comment?

+0

Ceci est une copie de [Comment utiliser la réflexion pour invoquer une méthode privée en C#?] (Http://stackoverflow.com/questions/135443/how-do-i-use-reflection-to-invoke- a-private-method-in-c) – jason

+0

Sont-ils dans la même DLL? Vous pourriez rendre SayHello() interne plutôt que privé si oui – wangburger

+0

Non, ils ne le sont pas. Je vais mettre à jour le code dans la question. –

Répondre

1

Vous n'avez pas inclus BindingFlags.Instance dans votre liste de drapeaux ... donc il n'y a pas d'instance ou de méthodes statiques à vérifier!

Personnellement, j'appelle généralement GetMethod puis MethodInfo.Invoke pour séparer la découverte de la méthode de l'invocation. Je trouve que cela facilite le débogage, mais YMMV.

échantillon complet:

using System; 
using System.Reflection; 

class OtherClass 
{ 
    private void Foo() 
    { 
     Console.WriteLine("OtherClass.Foo"); 
    } 
} 

class Test 
{ 
    static void Main() 
    { 
     OtherClass target = new OtherClass(); 
     typeof(OtherClass).InvokeMember("Foo", 
      BindingFlags.InvokeMethod | BindingFlags.Instance | 
      BindingFlags.Public | BindingFlags.NonPublic, 
      null, target, new object[0]); 
    } 
} 

Ou utiliser mon "chercher séparée de l'invocation":

using System; 
using System.Reflection; 

class OtherClass 
{ 
    private void Foo() 
    { 
     Console.WriteLine("OtherClass.Foo"); 
    } 
} 

class Test 
{ 
    static void Main() 
    { 
     OtherClass target = new OtherClass(); 
     MethodInfo method = typeof(OtherClass).GetMethod("Foo", 
      BindingFlags.InvokeMethod | BindingFlags.Instance | 
      BindingFlags.Public | BindingFlags.NonPublic); 

     // Could now check for method being null etc 
     method.Invoke(target, null); 
    } 
} 
+0

Je devrais savoir mieux ... Je ne peux pas battre Jon Skeet à l'un de ceux-ci! –

0

Vous avez oublié d'ajouter BindingFlags.Instance à la liste des drapeaux:

t.InvokeMember("SayHello", 
       BindingFlags.Intance | 
        BindingFlags.InvokeMethod | 
        BindingFlags.NonPublic, 
       null, 
       myReferencedForm1, 
       new object[] { }); 

Mais, pour être honnête, je préfère obtenir la méthode, puis en utilisant l'objet MethodInfo retourné pour appeler la méthode:

if(myReferencedForm1 != null) 
{ 
    var type = typeof(Form1); 
    var method = type.GetMethod("SayHello", BindingFlags.Instance 
     | BindingFlags.NonPublic); 

    method.Invoke(myReferencedForm1); 
} 
0

Le paramètre invokeAttr doit être

BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.NonPublic 
2

Ne pas essayer. Créer une interface: IPluginHost avec DoMethod(string Name) membre. Implémentez cette interface pour chaque formulaire, vous pouvez même l'extraire dans l'autre fichier en utilisant la déclaration partial class.

Dans la méthode impl, faites un simple changement de cas pour lancer la méthode appropriée. Utilisez un script pour le générer.

public interface IPluginHost 
{ 
    void DoMethod(string MethodName); 
} 

public partial MyForm:Form, IPluginHost 
{ 
    #region IPluginHost implementation 
    public void DoMethod(string MethodName) 
    { 
     switch (MethodName) 
      case "SayHello": 
       SayHello(); 
       break; 
      ... 
    } 
    #endregion 
} 

si vous faites l'architecture - ne HACK pas dès le début.

+1

+1 Je suis d'accord, pourquoi y aller d'une manière dure/sale quand il y a une manière beaucoup plus facile/propre comme ceci. – Doggett

0

Changer vos BindingFlags à

private CallMember() 
{ 
    Type t = typeof(Form1); //I guess I can also call 'myReferencedForm1.GetType(); 
    t.InvokeMember("SayHello", 
        System.Reflection.BindingFlags.InvokeMethod | 
        System.Reflection.BindingFlags.Instance | 
        System.Reflection.BindingFlags.NonPublic, 
        null, myReferencedForm1, new object[] { }); 
} 

Cela devrait faire l'affaire.