• 弱事件应用 WeakEvent


    目的

    实例在失去作用域后能被回收,实例引用的事件也能自动释放掉;

    场景

    1. 用到了一个现有的类型(发布者,无法修改源码);
    2. 无法决定什么时候释放此类型(发布者)的实例;
    3. 一旦监听此类型事件,将产生内存泄漏,导致自己的类型的实例(订阅者)无法释放。

    用法

    1. 发布者层(可以修改源码时),事件源定义事件时候用弱事件WeakEvent,这可以使得此事件不会强引用事件的订阅者;

    注意:WeakEvent通过委托得到目标实例对象,委托不能是静态方法,即订阅者必须是一个对象,否则会导致null异常;

    1. 订阅者层,使用弱事件中继WeakEventRelay,为发布者提供弱事件支持;

    注意:WeakEventRelay中继发布者时,重定义的委托事件的方法标识要保持不变,以确保事件与处理事件的订阅方法相关联;

    用法1

    发布者内部封装,外部+=正常调用;

    单个参数

    原型

    // Publisher
    public event Action<string> MyEvent;
    // Subscriber
    var publisher = new PublisherClass();
    publisher.MyEvent += PublisherClass_MyEvent;
    // Invoke
    private void PublisherClass_MyEvent(string arg){ }

    转换

    private readonly WeakEvent<string> _myEvent = new WeakEvent<string>();
    public event EventHandler<string> MyEvent
    {
        add => _myEvent.Add(value, value.Invoke);
        remove => _myEvent.Remove(value);
    }
    private void OnMyEvent()
    {
        _myEvent.Invoke(this, "");
    }
    

    Demo

    // Subscriber
    var publisher = new PublisherClass();
    publisher.MyEvent += PublisherClass_MyEvent;
    private void PublisherClass_MyEvent(object sender, string arg)
    {
    }
    

    多个参数

    原型

    public event Action<string, int> MyEvent;

    转换

    private readonly WeakEvent<MyEventArgs> _myEvent = new WeakEvent<MyEventArgs>();
    public event EventHandler<MyEventArgs> MyEvent
    {
        add => _myEvent.Add(value, value.Invoke);
        remove => _myEvent.Remove(value);
    }
    private void OnMyEvent()
    {
        _myEvent.Invoke(this, new MyEventArgs("", 1));
    }
    // 事件生成的数据
    public class MyEventArgs : EventArgs
    {
        public MyEventArgs(string arg1, int arg2)
        {
            Arg1 = arg1;
            Arg2 = arg2;
        }
        public string Arg1 { get; }
        public int Arg2 { get; }
    }
    

    Demo

    var publisher = new PublisherClass();
    publisher.MyEvent += PublisherClass_MyEvent;
    private void PublisherClass_MyEvent(object sender, MyEventArgs e)
    { 
    }
    

    用法2

    发布者外部中继,+=正常调用;
    原型

    XXX publisher = new XXX(){}
    publisher.EventName1 += XXX_EventName1;
    private void XXX_EventName1(object sender, XXEventArgs e) { }

    转换

    // 订阅者引用弱事件中继,对应需要被弱化的事件源类型(发布者)
    internal sealed class XXXWeakEventRelay : WeakEventRelay<XXX>
    {
        // 重载
        public XXXWeakEventRelay(XXX eventSource) : base(eventSource)
        {
        }
        // 弱事件字段,泛型参数是发布者事件参数的类型,而不是事件处理委托类型
        private readonly WeakEvent<XXEventArgs> _eventName1 = new WeakEvent<XXEventArgs>();
        // 对外公开的事件,同发布者定义的事件
        public event XXEventHandler EventName1
        {
            add => Subscribe(o => o.EventName1 += OnEventName1, () => _eventName1.Add(value, value.Invoke));
            remove => _eventName1.Remove(value);
        }
        // 事件处理函数
        private void OnEventName1(object sender, XXEventArgs e)
        {
            TryInvoke(_eventName1, sender, e);
        }
        // 订阅者实例被回收后,确保注销发布者中的事件
        protected override void OnReferenceLost(XXX source)
        {
            source.EventName1 -= OnEventName1;
            // 其他中继的事件注销
        }
    }
    

    Demo

    var weakEvent = new XXXWeakEventRelay(publisher);
    weakEvent.EventName1 += XXX_EventName1;
    

    注意:
    WeakEventsWeakEventRelay需要启用可空引用

    .NET/C# 利用 Walterlv.WeakEvents 高性能地定义和使用弱事件
    .NET/C# 利用 Walterlv.WeakEvents 高性能地中转一个自定义的弱事件(可让任意 CLR 事件成为弱事件)
    .NET 设计一套高性能的弱事件机制

  • 相关阅读:
    sqlserver 分页
    sqlserver 用FOR XML PATH('')多行并成一列
    yarn的安装和使用
    redis安装及基本使用
    dbeaver 的界面乱码
    cypress测试框架(一)
    外网访问VMware虚拟机的Web服务---系列操作
    将博客搬至CSDN
    textgrid-python模块基础使用
    opencv通过mask掩码图合成两张图
  • 原文地址:https://www.cnblogs.com/wesson2019-blog/p/14639952.html
Copyright © 2020-2023  润新知