大家可能都遇到过没有取消事件监听而带来的一些问题,像内存泄露、访问无效数据等。当我们写下如下代码时:
source.StateChanged += observer.SourceStateChangedHandler
实际上source会保持有对observer的一个引用,所以如果source的生命期长于observer的话,则当其它地方不引用observer时,如果不显示解除监听,则observer不会被垃圾回收。这可能会带来两个问题:其一,如果observer占用了大量内存的话,则这部分内存不会被释放;其二,程序的其它地方可能已经处于不一致的状态,这样当source.StateChanged事件再次发生时,observer.SourceStateChanged方法仍然会被调用,而此方法内部的逻辑可能会造成异常。
当然最直接的办法是在不使用observer时显示解除监听,像下面那样:
source.StateChanged -= observer.SourceStateChangedHandler
但程序员经常会忘记这一点。所以便有了“弱事件监听器”的概念,我们期望在监听时多做些工作,然后能达到自动取消监听的目的。废话不说,先上代码。
/// <summary> /// 当弱监听器发现被包装的监听者已经被垃圾收集时所调用的委托。 /// </summary> /// <typeparam name="E">事件参数类型。</typeparam> /// <param name="handler">MakeWeak方法返回的事件处理函数,提供此委托的地方 /// 要负责把此对象从被监听对象的事件处理方法列表中移除。</param> /// <param name="param">在调用MakeWeak方法时传入的额外参数。</param> public delegate void UnregisterCallback<E>(EventHandler<E> handler, object param) where E : EventArgs; /// <summary> /// 当进行事件处理时,如果被监听对象的生命期比监听器的生命周期长,我们就必 /// 须在监听器的生命期内取消对被监听对象的事件监听,否则被监听对象会持有监 /// 听器的一个强引用,而阻止它被垃圾收集。但有时我们经常忘记取消事件监听, /// 或者不容易确定何时解除监听。此时可以使用弱监听器,把如下代码: /// <code> /// observed.SomeEvent += observer.SomeEventHandler; /// </code> /// 改为: /// <code> /// observed.SomeEvent += WeakEventHandlerFactory.MakeWeak( /// observer.SomeEventHandler, /// (handler, param) => observed.SomeEvent -= handler, /// null); /// </code> /// 上面的代码使用了lambda表达式以捕获变量,也可以像下面那样使用param参数: /// <code> /// observed.SomeEvent += WeakEventHandlerFactory.MakeWeak( /// observer.SomeEventHandler, /// OnUnregisterWeakEvent, /// observed); /// /// void OnUnregisterWeakEvent(EventHandler<E> handler, object param) /// { /// ((ObservedType)param).SomeEvent -= handler; /// } /// </code> /// 或者使用如下形式: /// <code> /// observed.SomeEvent += WeakEventHandlerFactory.MakeWeak2( /// observer.SomeEventHandler, observed, "SomeEvent"); /// </code> /// 其中MakeWeak的第二个参数将弱监听器从事件源中移除。即使将第二个参数指定 /// 为null,也不会阻止observer对象被垃圾收集,但事件源中将始终保持一个轻量 /// 对象的引用。 /// </summary> public static class WeakEventHandlerFactory { /// <summary> /// 我们在MakeWeak方法中使用反射创建WeakEventHandler的实例,所以在(1) /// 处理无法指定泛型参数T,以完成转换,此接口用于简化这一步骤。 /// </summary> /// <typeparam name="E">事件参数类型。</typeparam> private interface IWeakEventHandler<E> where E : EventArgs { /// <summary> /// 事件处理器。 /// </summary> EventHandler<E> Handler { get; } } /// <summary> /// 对指定的事件处理函数创建一个弱监听器。 /// </summary> /// <typeparam name="E">事件参数类型。</typeparam> /// <param name="handler">被包装的事件处理器。</param> /// <param name="unregister">用于将弱监听器从事件源中移除的委托。可以指 /// 定为null,这时事件源中将始终保持一个轻量对象的引用,但不会阻止被包 /// 装的对象被垃圾收集。</param> /// <param name="param">在调用unregister时使用的额外参数,可以是null。</param> /// <returns>生成的弱监听器。</returns> public static EventHandler<E> MakeWeak<E>(EventHandler<E> handler, UnregisterCallback<E> unregister, object param) where E : EventArgs { if (handler == null) { throw new ArgumentNullException("handler"); } if (handler.Method.IsStatic || handler.Target == null) { throw new ArgumentException("Only instance methods are supported.", "handler"); } var type = typeof(WeakEventHandler<,>).MakeGenericType( handler.Method.DeclaringType, typeof(E)); var wehConstructor = type.GetConstructor( new[] { typeof(EventHandler<E>), typeof(UnregisterCallback<E>), typeof(object) }); // (1) var weak = (IWeakEventHandler<E>)wehConstructor.Invoke( new [] { handler, unregister, param }); return weak.Handler; } /// <summary> /// 此方法相当于MakeWeak(handler, unregister, null)。 /// </summary> public static EventHandler<E> MakeWeak<E>(EventHandler<E> handler, UnregisterCallback<E> unregister) where E : EventArgs { return MakeWeak(handler, unregister, (object)null); } /// <summary> /// 使用CreateUnregisterCallback创建取消弱监听器委托的形式注册监听器。 /// </summary> /// <typeparam name="E">事件参数类型。</typeparam> /// <param name="handler">被包装的事件处理器。</param> /// <param name="observed">被监听的对象。</param> /// <param name="eventName">监听的事件名称。</param> /// <returns>生成的弱监听器。</returns> public static EventHandler<E> MakeWeak2<E>(EventHandler<E> handler, object observed, string eventName) where E : EventArgs { return MakeWeak(handler, CreateUnregisterCallback<E>(observed, eventName)); } /// <summary> /// 创建一个用于取消弱监听器注册的委托。 /// </summary> /// <typeparam name="E">事件参数类型。</typeparam> /// <param name="observed">被监听的对象。</param> /// <param name="eventName">监听的事件名称。</param> /// <returns>创建结果,不会是null。</returns> public static UnregisterCallback<E> CreateUnregisterCallback<E>( object observed, string eventName) where E : EventArgs { return new UnregisterHelper<E>(observed, eventName).Callback; } /// <summary> /// 用于将弱监听器从事件源中移除的辅助类,在C++/CLI等不支持lambda表示式 /// 和自动委托的语言中,使用弱监听器的语法可能很复杂,此类用于简化这种 /// 情况。 /// </summary> /// <typeparam name="E">委托事件参数类型。</typeparam> private class UnregisterHelper<E> where E : EventArgs { /// <summary> /// 被监听的对象。 /// </summary> private readonly object observed; /// <summary> /// 事件名称。 /// </summary> private readonly string eventName; /// <summary> /// 构造函数。 /// </summary> internal UnregisterHelper(object observed, string eventName) { this.observed = observed; this.eventName = eventName; } /// <summary> /// 用于取消监听的委托。 /// </summary> internal UnregisterCallback<E> Callback { get { return (handler, param) => { var info = observed.GetType().GetEvent(eventName); info.RemoveEventHandler(observed, handler); }; } } } /// <summary> /// 弱事件监听器。 /// </summary> /// <typeparam name="T">监听者的类型。</typeparam> /// <typeparam name="E">事件参数类型。</typeparam> private class WeakEventHandler<T, E> : IWeakEventHandler<E> where T : class where E : EventArgs { /// <summary> /// 对监听器的弱引用。 /// </summary> private readonly WeakReference weakReference; /// <summary> /// 用于调用被包装的监听器的委托。 /// </summary> private readonly OpenEventHandler openHandler; /// <summary> /// 调用unregister时的额外参数。 /// </summary> private readonly object param; /// <summary> /// 监听器移除委托。 /// </summary> private UnregisterCallback<E> unregister; /// <summary> /// 构造函数。 /// </summary> /// <param name="handler">被包装的事件处理器。</param> /// <param name="unregister">用于移除弱监听器的代码。</param> /// <param name="param">调用unregister时的额外参数。</param> public WeakEventHandler(EventHandler<E> handler, UnregisterCallback<E> unregister, object param) { weakReference = new WeakReference(handler.Target); openHandler = (OpenEventHandler)Delegate.CreateDelegate( typeof(OpenEventHandler), null, handler.Method); Handler = Invoke; this.unregister = unregister; this.param = param; } /// <summary> /// 包装监听器事件处理函数的开放委托类型。 /// </summary> private delegate void OpenEventHandler(T @this, object sender, E e); /// <summary> /// <see>IWeakEventHandler.Handler</see> /// </summary> public EventHandler<E> Handler { get; private set; } /// <summary> /// 弱监听器事件处理函数。 /// </summary> /// <param name="sender">引发事件的对象。</param> /// <param name="e">事件参数。</param> private void Invoke(object sender, E e) { T target = (T)weakReference.Target; if (target != null) { openHandler.Invoke(target, sender, e); } else if (unregister != null) { unregister(Handler, param); unregister = null; } } } }
以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索参数
, 事件
, handler
, 旁路监听
, 事件监听
, 监听
, 监听器
, 计算器监听事件
, 弱一致性
, 监听fiddlerhttpclient
, 监听器事件
, eventhandler
, 弱类型
弱引用实例
java事件监听器原理、activiti 事件监听器、android事件监听器、javascript事件监听器、js事件监听器,以便于您获取更多的相关知识。