WPF 弱事件模式简介

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;

namespace weakEventTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        // 消息发布者
        Publisher publisher = new Publisher();

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

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

        private void btnNormal_Click(object sender, EventArgs e)
        {
            // 创建普通消息订阅者,并绑定到事件源
            normalSubscriber = new Subscriber("普通订阅者");
            publisher.SampleEvent += normalSubscriber.Receiver;
            Console.WriteLine("普通订阅者初始化并绑定事件");
        }

        private void btnWeakEvent_Click(object sender, EventArgs e)
        {
            // 创建弱事件消息订阅者,并添加到事件源
            weakSubscriber = new Subscriber("弱引用订阅者");
            WeakCarInfoEventManager.AddListener(publisher, weakSubscriber);
            Console.WriteLine("弱引用订阅者初始化并绑定事件");
        }

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

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

            // 尝试将弱事件订阅者销毁,并使用GC回收,GC成功将对象回收
            weakSubscriber = null;
            Console.WriteLine("将弱引用订阅者置为null");
            GC.Collect();
        }

        private void btnRiseEvent_Click(object sender, EventArgs e)
        {
            // 触发事件
            publisher.RaiseEvent();
            Console.WriteLine("手动触发发布者事件");
        }

      
    }

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

        public virtual void RaiseEvent()
        {
            SampleEvent?.Invoke(this,new EventArgs());
        }
    }

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

        public void Receiver(object sender, EventArgs e)
        {
            Console.WriteLine("Subscriber: " + SubName + "接受到了事件通知");
        }

        //通过该方法来处理弱事件管理器推送过来的订阅信息
        public bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
        {
            Receiver(sender,e);
            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;
        }
    }


}

如上,winform代码.

界面如下:

按顺序点击按钮,先初始化两个订阅类,并绑定publisher事件

然后将两个订阅者置为null,并执行GC

此时按道理来说,订阅者应该收不到消息了,因为已经被回收了。

但是因为publisher.event += subscriber.xxx 

实际上导致 subscriber被人引用了,所以实际上是无法回收的。

通过第四步,手动执行事件,可以看出普通的订阅类依旧 还是会收到消息通知

但是继承了弱事件接口(IweakListener)的类,确实被回收了。

所以综上所述,弱引用模式引入,可以解决一些事件订阅后,我们要销毁订阅者类,但是实际没被回收的内存泄漏问题。

缺点:

需要引入一个接口,和一个管理类,代码结构上有些繁琐,而且看了下管理类的源码,内部较为复杂且使用了较多的反射

个人还是建议直接用减等于这种显示的写法, publisher.event -= subscriber.xxx 。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值