zoukankan      html  css  js  c++  java
  • 弱事件应用 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 设计一套高性能的弱事件机制

  • 相关阅读:
    HTTPS原理浅析
    Java8 HashMap源码分析
    Java8 ArrayList源码分析
    Java反射
    Java泛型
    Tensorflow卷积神经网络
    Java8 Stream简介
    java.io与网络通信
    Python实现RNN
    域名系统DNS简介
  • 原文地址:https://www.cnblogs.com/wesson2019-blog/p/14639952.html
Copyright © 2011-2022 走看看