Поднять событие через отражение в c # - PullRequest
6 голосов
/ 25 февраля 2011

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

После поиска я обнаружил похожий вопрос: Как вызвать событие с помощью отражения в .NET / C #?

Это работает, пока я не зарегистрирую обработчик событий в элементе управления WinForm и не попытаюсь вызвать его. Закрытое поле '<EventName>' просто исчезает.

Ниже приведен упрощенный код, который воспроизводит проблему:

Program.cs:

public static void Main()
{
    Control control = new Control();
    control.Click += new EventHandler(control_Click);

    MethodInfo eventInvoker = ReflectionHelper.GetEventInvoker(control, "Click");
    eventInvoker.Invoke(control, new object[] {null, null});
}

static void control_Click(object sender, EventArgs e)
{
    Console.WriteLine("Clicked !!!!!!!!!!!");
}

Вот мой класс ReflectionHelper:

public static class ReflectionHelper
{
    /// <summary>
    /// Gets method that will be invoked the event is raised.
    /// </summary>
    /// <param name="obj">Object that contains the event.</param>
    /// <param name="eventName">Event Name.</param>
    /// <returns></returns>
    public static MethodInfo GetEventInvoker(object obj, string eventName)
    {
        // --- Begin parameters checking code -----------------------------
        Debug.Assert(obj != null);
        Debug.Assert(!string.IsNullOrEmpty(eventName));
        // --- End parameters checking code -------------------------------

        // prepare current processing type
        Type currentType = obj.GetType();

        // try to get special event decleration
        while (true)
        {
            FieldInfo fieldInfo = currentType.GetField(eventName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.GetField);

            if (fieldInfo == null)
            {
                if (currentType.BaseType != null)
                {
                    // move deeper
                    currentType = currentType.BaseType;
                    continue;
                }

                Debug.Fail(string.Format("Not found event named {0} in object type {1}", eventName, obj));
                return null;
            }

            // found
            return ((MulticastDelegate)fieldInfo.GetValue(obj)).Method;
        }
    }

Дополнительная информация:

  • Событие в том же классе: сработало.
  • Событие в другом классе, подкласс в той же сборке: сработало.
  • Событие в MY другой сборке, режиме отладки и выпуска: сработало.
  • Событие в WinForm, DevExpress, ...: не работает

Любая помощь приветствуется.

Ответы [ 2 ]

1 голос
/ 25 февраля 2011

События в WinForms обычно переопределяются и не имеют поддержки делегатов один-к-одному.Вместо этого у класса (в основном) есть словарь отображений событий-> делегатов, и делегаты создаются только при добавлении событий.Таким образом, вы не можете предполагать, что есть делегат, поддерживающий событие, как только вы получите доступ к полю с отражением.

Редактировать: это становится жертвой той же проблемы, но лучше, чем получить его как поле и привести его.

  var eventInfo = currentType.GetEvent(eventName); 
  var eventRaiseMethod = eventInfo.GetRaiseMethod()
  eventRaiseMethod.Invoke()
0 голосов
/ 25 февраля 2011

Вот код, который у меня был. 'obj' - это объект, для которого вы хотите вызвать метод, а 'methodName' - это метод, который вы хотите вызвать:

public void Invoke(Object obj, String methodName) {
    MethodInfo m = obj.GetType().GetMethod(methodName);

    if (m != null) {
        m.Invoke(obj, null);
    }
}

Пример использования:

String s = " test string ";
Invoke(s, "Trim");

Я не проверял это в разных сборках, но проект, из которого я брал его, был протестирован, и он отлично работал.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...