Как я могу передать событие в функцию в C #? - PullRequest
20 голосов
/ 08 марта 2009

Я хочу передать событие вспомогательной функции. Эта функция прикрепит метод к событию. Тем не менее, у меня возникают проблемы с передачей события. Я попытался передать EventHandler<TEventArgs>. Он компилируется, но события не прикрепляются (но все еще добавляются; кажется, что копия обработчика событий создана).

Например, если у меня есть это:

public event EventHandler<EventArgs> MyEvent;

И вспомогательная функция:

public static void MyHelperFunction<TEventArgs>(EventHandler<TEventArgs> eventToAttachTo)
{
    eventToAttachTo += (sender, e) => { Console.WriteLine("Hello world"); };
}

И звонящий:

MyHelperFunction(MyEvent);
MyEvent(null, new EventArgs()); // Does nothing.

Ответы [ 7 ]

17 голосов
/ 08 марта 2009

Причиной, по которой это не работает, является + = при применении к делегату создает новый делегат, который является комбинацией старого и нового. Он не изменяет существующий делегат.

Чтобы заставить это работать, вам нужно передать делегата по ссылке.

public static void Helper(ref EventHandler<EventArgs> e)
{
    e+= (x,y) => {};
}

Причина, по которой это работает вне метода, заключается в том, что LHS все еще является фактическим полем. Поэтому + = создаст нового делегата и вернет его обратно в поле участника.

3 голосов
/ 01 декабря 2011

Только что придумал этого маленького помощника. Если это ваше собственное событие, вы можете использовать такую ​​обертку. Вы можете использовать свои операторы + = для подключения обработчиков как обычно, но можете обернуть обертку и даже вызвать событие из другого места.

public class GenericEvent<T> where T:EventArgs
{
    public event EventHandler<T> Source = delegate { };

    public void Raise(object sender, T arg = default(T))
    {
        Source(sender, arg);
    }

    public void Raise(T arg = default(T))
    {
        Source(this, arg);
    }

    public void AddHandler(EventHandler<T> handler)
    {
        Source += handler;
    }

    public void RemoveHandler(EventHandler<T> handler)
    {
        Source -= handler;
    }

    public static GenericEvent<T> operator +(GenericEvent<T> genericEvent, EventHandler<T> handler)
    {
        genericEvent.AddHandler(handler);
        return genericEvent;
    }
}

Создать событие как:

public GenericEvent<EventArgs> MyEvent = new GenericEvent<EventArgs>();

Присоединить обработчики:

MyEvent += (s,e) => {};

Поднять событие:

MyEvent.Raise();
2 голосов
/ 21 июня 2011

Это не совсем хорошо, но вы можете использовать отражение, чтобы сделать это.

    public EventMonitor(object eventObject, string eventName)
    {
        _eventObject = eventObject;
        _waitEvent = eventObject.GetType().GetEvent(eventName);

        _handler = new EventHandler(SetEvent);
        _waitEvent.AddEventHandler(eventObject, _handler);
    }

Где eventObject - это объект, содержащий событие, а eventName - имя события. SetEvent - ваш обработчик событий.

У меня также есть способ избавиться от этого:

    public void Dispose()
    {
        _waitEvent.RemoveEventHandler(_eventObject, _handler);
    }
2 голосов
/ 08 марта 2009

Просто угадаю: вы пытались передать его как ref?

public static void MyHelperFunction<TEventArgs>(ref EventHandler<TEventArgs> eventToAttachTo)

MyHelperFunction(ref MyEvent);
1 голос
/ 06 августа 2013

передать что-то вроде Action e = e => myevent + = e; А вызов из метода с обработчиком? Преимущество работы с классами .NET.

1 голос
/ 27 октября 2011

Как отмечают многие, передача события в метод либо невозможна, либо не проста.

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

    void Register()
    {
        var super = new SuperHandler();
    
        //not valid syntax:
        super.HandleEvent(MyEvent1);
        super.HandleEvent(MyEvent2);
        super.HandleEvent(MyEvent3);
        super.HandleEvent(MyEvent4);
    }
    

    Вы можете сделать это, просто сделав ваши намеченные общие обработчики событий общедоступными (или внутренне, если хотите):

     public static class GenericHandler
     {
         public static void HandleAnyEvent(object sender, EventArgs e)
         {
             //handle
         }
     }
    
     public class SomeClass
     {
         void RegisterEvents()
         {
             var r = new EventRaiser();
    
             r.ImportantThingHappened += GenericHandler.HandleAnyEvent;
         }
     }
    

    В этом примере мой универсальный обработчик находится в статическом классе, но вы также можете использовать нестатический класс. Кроме того, я вижу, что в вашем примере вы сделали метод универсальным (TEventArgs). Поскольку все производные EventHandler (такие как CancelEventHandler) соответствуют базовому EventHandler, вам не нужно привлекать дженерики (и это не будет полезно).

  2. Если логика регистрации сложна или вы должны сохранять EventHandler закрытым, рассмотрите возможность использования События интерфейса . Это может не соответствовать вашей намеченной цели по сокращению объема кода, но позволит вам создать класс, который может предсказуемо обрабатывать все события определенного типа.

    interface IRaiseEvents
    {
        event EventHandler ConnectionCreated;
        event EventHandler ConnectionLost;
    }
    
    public class SuperHandler
    {
        void RegisterEvents(IRaiseEvents raiser)
        {
            raiser.ConnectionCreated += (sender, args) => Console.WriteLine("Connected.");
            raiser.ConnectionLost += (sender, args) => Console.WriteLine("Disconnected.");
        }
    }
    
1 голос
/ 12 ноября 2010

У меня есть решение, где у меня есть два интерфейса. Первый интерфейс имеет методы для привязки определенных событий, в то время как другой интерфейс имеет методы событий, которые могут быть связаны с этими событиями.

Методы связывания первого интерфейса принимают второй интерфейс в качестве параметра, что позволяет связывать события с методами событий любого класса, реализующего второй интерфейс.

Это понятно, или вы бы предпочли какой-нибудь код? :)

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