简体   繁体   English

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

[英]How can I pass an event to a function in C#?

I am looking to pass an event to a helper function.我希望将事件传递给助手 function。 This function will attach a method to the event.此 function 将向事件附加一个方法。 However, I am having trouble properly passing the event.但是,我无法正确通过该活动。 I have tried passing a EventHandler<TEventArgs> .我试过传递一个EventHandler<TEventArgs> It compiles, but events are not attached (but are still added; it seems a copy of the event handler is made).它可以编译,但未附加事件(但仍会添加;似乎制作了事件处理程序的副本)。

For example, if I have this:例如,如果我有这个:

public event EventHandler<EventArgs> MyEvent;

And the helper function:和助手 function:

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

And the caller:和来电者:

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

The reason why this does not work is += when applied to a delegate creates a new delegate which is the combination of the old and the new.这不起作用的原因是 += 当应用于委托时会创建一个新委托,它是旧委托和新委托的组合。 It does not modify the existing delegate.它不会修改现有的委托。

In order to get this to work you will have to pass the delegate by reference.为了使它起作用,您必须通过引用传递委托。

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

The reason this works outside of the method is because the LHS is still the actual field.这在方法之外起作用的原因是因为 LHS 仍然是实际字段。 So += will create a new delegate and assign back to the member field.所以 += 将创建一个新的委托并分配回成员字段。

Just came up with this little helper.刚刚想出了这个小帮手。 If it is your self-created Event you could use a wrapper like this.如果它是您自己创建的事件,您可以使用这样的包装器。 You can use your += operators to attach handlers as normal but can pass the wrapper around and even raise the event from elsewhere.您可以像往常一样使用 += 运算符附加处理程序,但可以传递包装器,甚至可以从其他地方引发事件。

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

Create the event like:创建事件,如:

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

Attach handlers:附加处理程序:

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

Raise event:提升事件:

MyEvent.Raise();

Just guessing: Have you tried passing it as ref?只是猜测:您是否尝试过将其作为参考传递?

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

MyHelperFunction(ref MyEvent);

It's not exactly nice, but you can use reflection to do this.这不是很好,但你可以使用反射来做到这一点。

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

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

Where eventObject is the object containing the event, and eventName is the name of the event.其中 eventObject 是包含事件的 object,eventName 是事件的名称。 SetEvent is your event handler. SetEvent 是您的事件处理程序。

I also have a dispose method like this:我也有这样的处理方法:

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

Pass something like Action e = e => myevent += e;传递类似 Action e = e => myevent += e; And call from method with the handler?并使用处理程序从方法调用? It has the benefit of working with .NET classes.它具有与 .NET 类一起使用的好处。

I have a solution where I have an two interfaces.我有一个解决方案,我有两个接口。 The first interface has methods for binding certain events, while the other interface has event methods that can be bound to those events.第一个接口具有绑定某些事件的方法,而另一个接口具有可以绑定到这些事件的事件方法。

The first interface's bind methods takes the second interface as parameter, which makes it possible to bind the events to the event methods of any class that implements the second interface.第一个接口的绑定方法将第二个接口作为参数,这使得可以将事件绑定到任何实现第二个接口的 class 的事件方法。

Is that understandable, or would you prefer some code?这是可以理解的,还是您更喜欢一些代码? :) :)

As many have pointed out, passing an event to a method is either not possible or not simple.正如许多人所指出的,将事件传递给方法要么是不可能的,要么并不简单。

  1. Please clarify, but I suspect your intended usage will look something like:请澄清,但我怀疑您的预期用途将类似于:

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

    You can accomplish this simply by making your intended generic event handlers accessible publicly (or internally, if you desire):您可以简单地通过使您的预期通用事件处理程序可公开访问(或在内部,如果您愿意)来实现:

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

    In this example my catch-all handler is in a static class, but you can just as well use a non-static class.在此示例中,我的包罗万象的处理程序位于 static class 中,但您也可以使用非静态 class。 Also, I see that in your example you have made the method generic (TEventArgs).另外,我看到在您的示例中,您已将方法设为通用(TEventArgs)。 Because all EventHandler derivatives (such as CancelEventHandler) match the base EventHandler, you do not need to involve generics (nor would it be helpful).因为所有 EventHandler 派生类(例如 CancelEventHandler)都与基本 EventHandler 匹配,所以您不需要涉及 generics(也不会有帮助)。

  2. If the registration logic is complex or you must keep the EventHandler private, consider using Interface Events .如果注册逻辑很复杂或者您必须保持 EventHandler 私有,请考虑使用接口事件 This may not meet your intended goal of reducing the amount of code, but it will allow you to create a class that can predictably handle all of the events of a specific type.这可能无法满足您减少代码量的预期目标,但它将允许您创建一个 class 可以预测地处理特定类型的所有事件。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在 Unity/C# 中传递要添加到事件的函数? - How do I pass a function to be added to an event in Unity/C#? C#:如何将类传递给单独dll中的函数 - C#: How can I pass a class to a function in separate dll 我如何将我的imageButton值传递给C#函数 - How can i pass my imagebutton values to c# function 在C#中,如何将类型化数组传递给泛型函数? - In C#, how can I pass typed array into generic function? 如何在C#中将文件/文件路径从一个Button_Click事件传递到另一个事件? - How can I pass a file/file path from one Button_Click event to another in C#? 如何正确地将输入参数传递给C#中的事件处理程序方法? - How can I correctly pass an input parameter to an event handler method in C#? 如何获取输入 onchange 事件以调用 c# 方法并将值传递给它 asp.net - How can i get input onchange event to call a c# method and pass a value into it asp.net C#中的多线程:如何将函数名称传递给另一个函数来启动新线程? - Multithreading in C#: How can I pass a function name to another function to start a new thread? 如何将C#函数指针传递给CLI / C ++代码? - How can I pass a C# function pointer into CLI/C++ code? 如何将值传递到c#中的图像按钮单击事件? - How Do I pass Values into an imagebutton click event in c#?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM