如何将事件传递给C#中的函数?

时间:2009-03-08 15:16:14

标签: c# delegates

我希望将事件传递给辅助函数。此函数将附加方法到事件。但是,我无法正确传递活动。我试过传递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 个答案:

答案 0 :(得分:17)

这不起作用的原因是+ =当应用于委托时创建一个新委托,它是旧的和新的组合。它不会修改现有的委托。

为了使其工作,您必须通过引用传递委托。

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

这种方法在方法之外工作的原因是因为LHS仍然是实际的领域。所以+ =将创建一个新的委托并分配回成员字段。

答案 1 :(得分:3)

刚出现这个小帮手。如果是你自己创建的事件,你可以使用这样的包装器。您可以使用+ =运算符正常附加处理程序,但可以传递包装器,甚至可以从其他地方引发事件。

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 :(得分:2)

猜测:您是否尝试将其作为参考传递?

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

MyHelperFunction(ref MyEvent);

答案 3 :(得分:2)

这不太好,但你可以使用反射来做到这一点。

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

答案 4 :(得分:1)

我有一个解决方案,我有两个接口。第一个接口具有绑定某些事件的方法,而另一个接口具有可以绑定到这些事件的事件方法。

第一个接口的bind方法将第二个接口作为参数,这样就可以将事件绑定到实现第二个接口的任何类的事件方法。

这是可以理解的,还是您更喜欢某些代码? :)

答案 5 :(得分:1)

许多人已经指出,将事件传递给方法要么不可能,要么不简单。

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

    在这个例子中,我的catch-all处理程序在一个静态类中,但你也可以使用非静态类。另外,我在你的例子中看到你使方法通用(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.");
        }
    }
    

答案 6 :(得分:1)

传递类似Action e = e =&gt;的内容myevent + = e; 并使用处理程序从方法调用?它具有使用.NET类的好处。