简体   繁体   English

动态订阅/取消订阅事件

[英]Dynamically subscribe/unsubscribe from events

I am working on a card game project in C#. 我正在使用C#开发纸牌游戏项目。 In this game, there are numerous events that are fired that the cards on the table need to subscribe to. 在这个游戏中,有很多事件需要触发,桌上的纸牌需要订阅。 However, I need the cards to dynamically subscribe and unsubscribe to the events so that the cards that are not currently active will not respond to the events being fired. 但是,我需要这些卡来动态地订阅和取消订阅事件,以便当前未激活的卡不会响应所触发的事件。

My solution for this is to use an EventManager parent class, with one child for each event. 我的解决方案是使用EventManager父类,每个事件有一个孩子。 Each of these managers will have subscribe / unsubscribe methods that take an EventHandler as a parameter. 这些管理器中的每一个都将具有将EventHandler作为参数的订阅/取消订阅方法。 When called, the methods will subscribe / unsubscribe the provided handlers from the event assigned to that manager. 调用时,这些方法将从分配给该管理器的事件中订阅/取消订阅提供的处理程序。

The code below is a basic Console application that uses the same design pattern as my card game, and has the same issues. 下面的代码是一个基本的控制台应用程序,该应用程序使用与我的纸牌游戏相同的设计模式,并且存在相同的问题。 You can paste it directly into Visual Studio and it will run. 您可以将其直接粘贴到Visual Studio中,然后它将运行。

using System;
using System.Collections.Generic;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var example = new ExampleCard();
            example.Subscribe();
            example.Events.FireEventOne(null, new EventArgs());
            example.UnSubscribe();
            example.Events.FireEventOne(null, new EventArgs());
            Console.ReadLine();
        }
    }

    public class EventContainer
    {
        public delegate void EventOne(Object sender, EventArgs r);
        public event EventOne OnEventOne;

        public EventContainer()
        {
            OnEventOne += Default_Handler;
        }

        public void Default_Handler(object sender, EventArgs e)
        {

        }

        public void FireEventOne(object sender, EventArgs e)
        {
            OnEventOne(sender, e);
        }
    }

    public class EventManager
    {
        protected EventContainer Events;

        public EventManager(EventContainer events)
        {
            Events = events;
        }

        public virtual void Subscribe(EventHandler handler)
        {
        }

        public virtual void Unsubscribe(EventHandler handler)
        {
        }
    }

    public class EventOneManager : EventManager
    {
        public EventOneManager(EventContainer events)
            : base(events)
        {
        }

        public override void Subscribe(EventHandler handler)
        {
            Events.OnEventOne += new EventContainer.EventOne(handler);
        }

        public override void Unsubscribe(EventHandler handler)
        {
            Events.OnEventOne -= new EventContainer.EventOne(handler);
        }
    }

    public class ExampleCard
    {
        public EventContainer Events = new EventContainer();
        private readonly List<EventManager> _subscribedEvents = new List<EventManager>();

        public ExampleCard()
        {
            _subscribedEvents.Add(new EventOneManager(Events));
        }

        public void Example_OnEventOneFired(object sender, EventArgs e)
        {
            Console.WriteLine("Event One was fired.");
        }

        public void Subscribe()
        {
            _subscribedEvents[0].Subscribe(Example_OnEventOneFired);
        }

        public void UnSubscribe()
        {
            _subscribedEvents[0].Unsubscribe(Example_OnEventOneFired);
        }
    }
}

EventOneManager.Subscribe() seems to work, but EventOneManager.Unsubscribe() does not; EventOneManager.Subscribe()似乎有效,但EventOneManager.Unsubscribe()无效; after calling that method, the example card stays subscribed to the event and I can't figure out why, or how to fix it. 调用该方法后,示例卡将继续订阅该事件,但我不知道原因或解决方法。

One thing I tried was removing the 'new EventContainer.EventOne' call making it look like this: 我尝试做的一件事是删除“ new EventContainer.EventOne”调用,使其看起来像这样:

public override void Unsubscribe(EventHandler handler)
            {
                Events.OnEventOne -= handler;
            }

But I get this error: Cannot implicitly convert type 'System.EventHandler' to 'ConsoleApplication1.EventContainer.EventOne" Any suggestions? 但是我收到此错误:无法将类型'System.EventHandler'隐式转换为'ConsoleApplication1.EventContainer.EventOne”有任​​何建议吗?

Also I would like to be able to use a custom EventArgs class, but I can't figure out how to pass in a generic handler which will work with any of the events I am using. 另外,我希望能够使用自定义EventArgs类,但是我无法弄清楚如何传递将与我正在使用的任何事件一起使用的通用处理程序。 This I can work around, but I would prefer to use custom EventArgs. 我可以解决此问题,但我更喜欢使用自定义EventArgs。

You need to change the event to be of type EventHandler . 您需要将事件更改为EventHandler类型。
You should not make your own delegate type. 您不应该创建自己的委托类型。

To pass additional data, use EventHandler<T> . 要传递其他数据,请使用EventHandler<T>

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

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