2

我在我的主要应用程序中拥有一堆具有私有和公共功能的表单。我有一个插件架构,可以在创建和加载每个表单时访问它,并保存对它的引用以更新它、添加控件等。

我们正在尝试做的是实现这个插件架构,但是一些插件可能需要调用表单的私有函数。这是我尝试使用 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 更轻松地做到这一点吗?如果有怎么办?

4

5 回答 5

2

不要那样做。

创建接口:IPluginHostwith DoMethod(string Name)member。为每个表单实现该接口,您甚至可以使用partial class声明将其提取到另一个文件中。

在方法 impl 中,做简单的 switch case 来踢出正确的方法。使用一些脚本来生成它。

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
}

如果你正在做架构- 不要一开始就破解它。

于 2010-12-01T18:15:05.510 回答
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);
    }
}
于 2010-12-01T18:12:49.677 回答
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);
}
于 2010-12-01T18:12:08.947 回答
0

invokeAttr参数应该是

BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.NonPublic
于 2010-12-01T18:14:26.563 回答
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[] { });
}

这应该可以解决问题。

于 2010-12-01T18:18:58.077 回答