Как прикрепить обработчик события к событию, используя отражение? - PullRequest
7 голосов
/ 25 июня 2010

Я знаю о EventInfo.AddEventHandler(...) методе, который можно использовать для прикрепления обработчика к событию. Но что делать, если я не могу даже определить правильную сигнатуру обработчика события, как, например, у меня даже нет ссылки на аргументы события, ожидаемые обработчиком?

Я объясню проблему с правильным кодом.

// Сценарий, когда в моем решении есть все, сценарий нулевого отражения.

internal class SendCommentsManager
{
    public void Customize(IRFQWindowManager rfqWindowManager)
    {
        rfqWindowManager.SendComment += HandleRfqSendComment;
    }

    private void HandleRfqSendComment(object sender, SendCommentEventArgs args)
    {
        args.Cancel = true;
    }
}

Теперь я хочу достичь той же цели, используя отражение. Мне удалось выяснить большую часть этого, но когда я присоединяю делегата к событию (используя AddEventHandler), он генерирует исключение "Error binding to target method.".

Я понимаю причину этого исключения, связывая неправильного делегата с событием. Но должен быть какой-то способ достичь этого.

 internal class SendCommentsManagerUsingReflection
 {
     public void Customize(IRFQWindowManager rfqWindowManager)
     {
         EventInfo eventInfo = rfqWindowManager.GetType().GetEvent("SendComment");
         eventInfo.AddEventHandler(rfqWindowManager, 
             Delegate.CreateDelegate(eventInfo.EventHandlerType, this, "HandleRfqSendComment"));
         //<<<<<<<<<<ABOVE LINE IS WHERE I AM GOING WRONG>>>>>>>>>>>>>>
     }

     private void HandleRfqSendComment(object sender, object args)
     {
         Type sendCommentArgsType = args.GetType();
         PropertyInfo cancelProperty = sendCommentArgsType.GetProperty("Cancel");
         cancelProperty.SetValue(args, true, null);
     }
 }

1 Ответ

10 голосов
/ 25 июня 2010

Я думаю, что ваш код не работает, потому что HandleRfqSendComment является приватным.Вместо этого вы можете напрямую создать делегата для этого метода, не передавая его имя CreateDelegate.Затем вам нужно будет преобразовать делегат в требуемый тип, используя следующий метод:

public static Delegate ConvertDelegate(Delegate originalDelegate, Type targetDelegateType)
{
    return Delegate.CreateDelegate(
        targetDelegateType,
        originalDelegate.Target,
        originalDelegate.Method);
}

В своем коде вы можете использовать этот метод следующим образом:

EventInfo eventInfo = rfqWindowManager.GetType().GetEvent("SendComment");
Action<object, object> handler = HandleRfqSendComment;
Delegate convertedHandler = ConvertDelegate(handler, eventInfo.EventHandlerType);
eventInfo.AddEventHandler(rfqWindowManager, convertedHandler);
...