Подтвердить что ты не робот

Как передать событие функции на С#?

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

Ответ 1

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

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

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

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

Ответ 2

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

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();

Ответ 3

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

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

MyHelperFunction(ref MyEvent);

Ответ 4

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

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

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

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

У меня также есть метод dispose:

    public void Dispose()
    {
        _waitEvent.RemoveEventHandler(_eventObject, _handler);
    }

Ответ 5

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

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

Является ли это понятным или вы предпочитаете какой-то код?:)

Ответ 6

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

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

    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;
         }
     }
    

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

  • Если логика регистрации сложна или вы должны держать Private 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.");
        }
    }
    

Ответ 7

Передайте что-то вроде Action e = e = > myevent + = e; И вызов из метода с обработчиком? Это полезно для работы с .NET-классами.