Есть ли способ вызвать закрытые функции формы или класса через Type.InvokeMember или сообщения в C #? - PullRequest
2 голосов
/ 01 декабря 2010

В моем основном приложении есть набор форм, которые имеют как частные, так и публичные функции.У меня есть подключаемая архитектура, которая обращается к каждой форме, когда она создается и загружается, и содержит ссылку на нее для ее обновления, добавления элементов управления и т. Д.

Что мы пытаемся сделать, это реализовать эту архитектуру подключаемого модуля, но некоторые плагины могут вызывать закрытые функции формы.Вот пример того, что я пробовал с 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.

Нужно ли создавать и использовать Binder?Если да, то как мне это сделать?Могу ли я сделать это проще с System.Windows.Forms.Message?Если так, то как?

Ответы [ 5 ]

2 голосов
/ 01 декабря 2010

Не пытайтесь это сделать.

Создайте интерфейс: IPluginHost с DoMethod(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
}

Если вы используете архитектуру - не взламывайте его с самого начала.

1 голос
/ 01 декабря 2010

Вы не включили 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 голосов
/ 01 декабря 2010

Измените свои 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[] { });
}

Это должно сработать.

0 голосов
/ 01 декабря 2010

Параметр invokeAttr должен быть

BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.NonPublic
0 голосов
/ 01 декабря 2010

Вы забыли добавить 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);
}
...