2010-12-01 22 views
2

我所擁有的是我的主應用程序中的一些表單,它們具有私人和公共功能。我有一個插件體系結構,它可以在創建和加載時訪問每個表單並持有對其進行更新,添加控件等的引用。有沒有辦法通過Type.InvokeMember或C#中的消息調用窗體或類的私有函數?

我們正在嘗試的是在體系結構中實現此插件,但一些插件可能需要調用窗體的私有函數。下面是我用Type.InvokeMember試過一個例子:

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

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

在另一個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[] { }); 
    } 
} 

我試圖"SayHello""SayHello()"他們都返回 'MissingMethodException' 錯誤:

Method 'Form1.SayHello()' not found. 

我是否需要創建並使用活頁夾?如果是這樣,我該怎麼做?我可以使用System.Windows.Forms.Message更簡單嗎?如果是這樣如何?

+0

這是[如何使用反射來調用C#中的私有方法?]的副本(http://stackoverflow.com/questions/135443/how-do-i-use-reflection-to-invoke- a-private-method-in-c) – jason 2010-12-01 18:11:39

+0

這些是在同一個dll中嗎?如果是這樣的話,你可以讓SayHello()內部而非私人的 – wangburger 2010-12-01 18:13:16

+0

不,他們不是。我將更新問題中的代碼。 – 2010-12-01 18:13:49

回答

1

您還沒有在旗標列表中包含BindingFlags.Instance ...所以它沒有實例或靜態方法來檢查!

我個人通常會撥打GetMethod然後MethodInfo.Invoke將方法的發現與調用分開。我發現這使得它更容易調試,但YMMV。

完整的示例:

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]); 
    } 
} 

還是用我的 「分開調用取」:

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

你忘了添加BindingFlags.Instance到標記列表:

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

不過,說實話,我喜歡得到的方法,然後使用MethodInfo對象返回給調用方法:

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

    method.Invoke(myReferencedForm1); 
} 
0

invokeAttr參數應該是

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

不要嘗試。

創建界面:IPluginHostDoMethod(string Name)成員。爲每個表單實現該接口,甚至可以使用partial class聲明將其提取到其他文件。

在方法impl中,做簡單的開關情況來踢適當的方法。使用一些腳本來生成它。

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 
} 

如果你正在做的架構 - 在一開始沒有本事。

0

更改您的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[] { }); 
} 

這應該做的伎倆。

相關問題