简体   繁体   English

c# 动态事件订阅和退订

[英]c# dynamic event subscription and unsubscription

I want to be able to have an object add one of its methods to an EventHandler that is passed to it and give said method the ability to remove itself from the EventHandler .我希望能够让 object 将其方法之一添加到传递给它的EventHandler并赋予所述方法从EventHandler中删除自身的能力。

public class EventRaiser {
    public event EventHandler event1
    public event EventHandler event2
    public void fire() {
        event1?.Invoke(this, null);
        event2?.Invoke(this, null);
    }
}

public class EventSubscriber {
    EventHandler eh;
    public EventSubscriber(EventHandler eh) {
        this.eh = eh;
        eh += receive;
    }

    public void receive(object obj, EventArgs data) {
        // Do stuff.
        if(condition) eh -= receive;
    }
}

public class MainClass {
    public void Main() {
        EventRaiser er = new EventRaiser();
        EventSubscriber es1 = new EventSubscriber(er.event1);
        EventSubscriber es2 = new EventSubscriber(er.event2);
        er.fire();
    }
}

The above code does not compile as I cannot even pass er.event1 or er.event2 to EventSubscriber ("The event can only appear in the left hand side of +=...").上面的代码无法编译,因为我什至无法将er.event1er.event2传递给EventSubscriber (“事件只能出现在 +=... 的左侧”)。 Removing the event keyword from the EventHandler s fixes this issue but unsubscribing does not work properly.EventHandler中删除event关键字可以解决此问题,但取消订阅无法正常工作。 Is there a way to make this work?有没有办法使这项工作? Use pointers maybe?也许使用指针?

The problem here comes from you passing an EventHandler , not the list holding the delegate s behind it itsself.这里的问题来自于你传递了一个EventHandler ,而不是在它本身后面包含delegate的列表。 Basically the "list of method pointers" to your handlers.基本上是处理程序的“方法指针列表”。

As you can see, in the declaration of event1 you have the keyword event , which is missing when you pass it somewhere else.如您所见,在event1的声明中,您有关键字event ,当您将它传递到其他地方时会丢失该关键字。 Unfortunately you cannot extract the " delegate holder" of an event easily.不幸的是,您无法轻松提取event的“ delegate持有人”。

Basically at the time you want to register your handler to an event you somehow need a compile time reference to it, in order to be able to += and -= to it.基本上,当您想将处理程序注册到某个事件时,您需要以某种方式对其进行编译时引用,以便能够对其进行+=-=

You could do the following:您可以执行以下操作:

public class EventRaiser
{
    public delegate void Event1(string args);
    public List<Event1> handlers = new List<Event1>();

    public void register(Event1 handler)
    {
        handlers.Add(handler);
    }

    public void unregister(Event1 handler)
    {
        handlers.Remove(handler);
    }
    
    public void fire()
    {
        handlers.ForEach(handler => handler("myEventArgs"));
    }
}
public class EventSubscriber
{
    Action<Event1> registerAction;
    Action<Event1> unregisterAction;
    public EventSubscriber(Action<Event1> register, Action<Event1> unregister)
    {
        registerAction = register;
        unregisterAction = unregister;
        registerAction(receive);
    }

    public void receive(string args)
    {
        // Do stuff.
        unregisterAction(receive);
    }
}
public class MainClass
{
    public void Main()
    {
        EventRaiser er = new EventRaiser();
        EventSubscriber es1 = new EventSubscriber(er.register, er.unregister);                
        er.fire();
    }
}

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM