/// <summary> /// 订阅弱事件处理函数。 /// </summary> /// <param name="originalHandler">原始处理函数,请始终传入 <code>value</code>。</param> /// <param name="castedHandler">可被隐式转换为 Action 的方法组,请始终传入 <code>value.Invoke</code>。</param> public void Add(MulticastDelegate originalHandler, Action <TSender, TArgs> castedHandler) { lock (_locker) { // 获取委托对应的目标实例。 var target = originalHandler.Target ?? throw new ArgumentException("无法将弱事件应用于没有对象的纯函数中。", nameof(originalHandler)); var method = originalHandler.Method; // 找到目前是否有已经存储过的对 target 的弱引用实例,如果有,我们将复用此实例,而不是加入到集合中。 // 注意,这里的判定使用的是 ReferenceEquals,因为 ConditionalWeakTable 的比较用的是此方法,这可以确保回收时机两者一致。 var reference = _relatedInstances.Find(x => x.TryGetTarget(out var instance) && ReferenceEquals(target, instance)); if (reference is null) { // 如果没有找到已经存储过的弱引用实例,我们将创建一个新的。 reference = new WeakReference <object>(target); _relatedInstances.Add(reference); var weakEventHandler = new WeakEventHandler(); weakEventHandler.Add(originalHandler, castedHandler); _handlers.Add(target, weakEventHandler); } else if (_handlers.TryGetValue(target, out var weakEventHandler)) { // 如果找到了已经存储过的弱引用实例,则为其添加一个新的事件处理器。 weakEventHandler.Add(originalHandler, castedHandler); } else { // 如果找不到弱引用实例,说明有一个已经被 GC 掉的对象竟然还能 += 事件。逗我?! throw new InvalidOperationException("有一个已经被 GC 掉的对象正在试图注册事件处理函数,可能代码写错了。"); } } }