C# 弱事件模式(一)认识弱事件模式

首先查看官网的解释:

In applications, it is possible that handlers that are attached to event sources will not be destroyed in coordination with the listener object that attached the handler to the source. This situation can lead to memory leaks. Windows Presentation Foundation (WPF) introduces a design pattern that can be used to address this issue, by providing a dedicated manager class for particular events and implementing an interface on listeners for that event. This design pattern is known as the weak event pattern.


在应用程序中,绑定事件源的处理程序没有一致性的销毁绑定到此处理程序的监听对象(人话:在监听对象释放时,Event处理程序并没有及时将监听对象移除),这种情况可能导致内存泄露。WPF引入了一个可以解决此类问题的设计模式,方法是为特定事件提供专门的管理类,并该事件的监听器实现一个接口。这种设计模式就是众所周知的弱事件模式

弱事件模式就是为了解决监听对象释放后没有及时在事件源中解除绑定导致内存泄露的问题
Talk is cheap, show me the code :
创建一个非常简单winform程序,界面如下:
这里写图片描述

    public partial class Wnd_Event : Form
    {
        public Wnd_Event()
        {
            InitializeComponent();
        }

        // 消息发布者
        Publisher publisher = new Publisher();

        // 普通消息订阅者
        Subscriber sub_common = null;

        // 弱事件消息订阅者
        Subscriber sub_weak = null;

        private void btn_NewSub_Click(object sender, EventArgs e)
        {
            // 创建普通消息订阅者,并绑定到事件源
            sub_common = new Subscriber("Common Event Subscribe");
            publisher.SampleEvent += sub_common.Recever;

            ShowMsg("Common Event Subscribe Init Success");
        }

        private void btn_DestorySub_Click(object sender, EventArgs e)
        {
            // 解除注册,GC将可以成功回收对象
            // publisher.SampleEvent -= sub_common.Recever;

            // 尝试将普通事件订阅者销毁并使用GC回收,实际GC没有将对象回收
            sub_common = null;
            GC.Collect();

            ShowMsg("Try To Destory Common Event Subscribe");
        }

        private void btn_NewWeakSub_Click(object sender, EventArgs e)
        {
            // 创建弱事件消息订阅者,并添加到事件源
            sub_weak = new Subscriber("Weak Event Subscribe");

            WeakCarInfoEventManager.AddListener(publisher, sub_weak);

            ShowMsg("Weak Event Subscribe Init Success");
        }

        private void btn_DestoryWeakSub_Click(object sender, EventArgs e)
        {
            // 尝试将弱事件订阅者销毁,并使用GC回收,GC成功将对象回收
            sub_weak = null;
            GC.Collect();

            ShowMsg("Try To Destory Weak Event Subscribe");
        }

        private void btn_RaiseEvent_Click(object sender, EventArgs e)
        {
            // 触发事件
            publisher.RaiseEvent();

            ShowMsg("Try To Destory Raise Event");
        }

        public static void ShowMsg(string msg)
        {
            Console.WriteLine("msg: " + msg);
        }
    }


    /// <summary>
    /// 事件发布者
    /// </summary>
    public class Publisher
    {
        public event EventHandler<EventArgs> SampleEvent;

        public virtual void RaiseEvent()
        {
            EventHandler<EventArgs> hevent = SampleEvent;
            if (hevent != null)
            {
                hevent(this, new EventArgs());
            }
        }
    }

    /// <summary>
    /// 事件订阅者
    /// </summary>
    public class Subscriber : IWeakEventListener
    {
        string SubName = "";

        public Subscriber() { }
        public Subscriber(string name) { SubName = name; }


        public void Recever(object sender, EventArgs e)
        {
            //MessageBox.Show(SubName + " Receiver Event");

            Console.WriteLine("Subscriber: " + SubName + " Receiver Event");
        }

        //通过该方法来处理弱事件管理器推送过来的订阅信息
        public bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
        {
            Recever(sender, e as EventArgs);
            return true;
        }
    }


    /// <summary>
    /// 事件弱管理器
    /// </summary>
    public class WeakCarInfoEventManager : WeakEventManager
    {
        /// <summary>
        /// 将订阅者添加到事件源
        /// </summary>
        /// <param name="source">发布者</param>
        /// <param name="listener">订阅者</param>
        public static void AddListener(object source, IWeakEventListener listener)
        {
            CurrentManager.ProtectedAddListener(source, listener);
        }

        public static void RemoveListener(object source, IWeakEventListener listener)
        {
            CurrentManager.ProtectedRemoveListener(source, listener);
        }

        /// <summary>
        /// 管理器
        /// </summary>
        public static WeakCarInfoEventManager CurrentManager
        {
            get
            {
                //从现有管理器中获取默认管理器对象
                var manager = GetCurrentManager(typeof(WeakCarInfoEventManager))
                    as WeakCarInfoEventManager;

                if (manager == null)
                {
                    manager = new WeakCarInfoEventManager();

                    //将新建的管理器对象设置为当前类型默认管理器
                    SetCurrentManager(typeof(WeakCarInfoEventManager), manager);
                }
                return manager;
            }
        }

        protected override void StartListening(object source)
        {
            //将发布者事件订阅到当前
            (source as Publisher).SampleEvent += CarDealer_NewCarInfo;
        }

        void CarDealer_NewCarInfo(object sender, EventArgs e)
        {
            DeliverEvent(sender, e);
        }

        protected override void StopListening(object source)
        {
            (source as Publisher).SampleEvent -= CarDealer_NewCarInfo;
        }
    }

这里写图片描述

结论:

  • 普通的事件订阅中,订阅者注册到事件源时存在强引用,若未解除注册,GC将不能及时回收订阅者实例
  • 弱事件模式下,订阅者和事件源之间不存在强引用,GC可以及时销毁订阅者实例
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值