. NET trap four-event listening problem and weak listener

Source: Internet
Author: User
Tags constructor event listener static class

You may have encountered some problems, such as memory leaks, accessing invalid data, and so on without canceling the event listening. When we write the following code:

Source. StateChanged + = Observer. Sourcestatechangedhandler

In fact, source maintains a reference to observer, so if the source lifetime is longer than observer, if the observer is not referenced elsewhere, observer will not be garbage collected if the listener is not displayed. This can lead to two problems: first, if observer consumes a lot of memory, that part of memory will not be released; second, the rest of the program may already be in an inconsistent state, such as source. StateChanged event occurs again when the observer. The Sourcestatechanged method is still invoked, and the logic inside this method can cause an exception.

The most straightforward approach, of course, is to display a release monitor without using the Observer, as follows:

Source. StateChanged-= Observer. Sourcestatechangedhandler

But programmers often forget that. So there is the concept of "weak event listener", we expect to do more work when listening, and then can achieve the purpose of automatic cancellation of listening. Nonsense do not say, first on the code.

<summary>///A delegate that is invoked when a weak listener discovers that the packaged listener has been garbage collected. </summary>///<typeparam name= "E" > event parameter type. </typeparam>///<param name= The event handler function returned by the "handler" >makeweak method, where this delegate is provided///is responsible for removing this object from the list of event-handling methods of the listener object. </param>///<param name= "param" > Additional parameters that are passed in when the Makeweak method is invoked.  </param> public delegate void Unregistercallback<e> (eventhandler<e> handler, object param) where E:   
        
 EventArgs; <summary>///When an event is processed, if the listener's life cycle is longer than the monitor's lifecycle, we must///the listener's life to cancel the event listening to the listening object, or the listener will hold a strong///listener Reference, and prevent it from being garbage collected. But sometimes we forget to cancel the event listening,///or it is not easy to determine when to release the listener. At this point you can use the weak listener, the following code:///<code>///observed. Someevent + = Observer.   
 Someeventhandler; </code>///changed to:///<code>///observed. Someevent + = Weakeventhandlerfactory.makeweak (///Observer. Someeventhandler,///(handler, param) => observed.   
 Someevent-= handler,///null);   </code>
 The code above uses a lambda expression to catch a variable, or you can use the Param parameter as follows:///<code>///observed. Someevent + = Weakeventhandlerfactory.makeweak (///Observer.   
 Someeventhandler,///onunregisterweakevent,///observed); void Onunregisterweakevent (eventhandler&lt; E&gt; Handler, object param)///{///((observedtype) param).   
 Someevent-= handler; ///</code>///or use the following form:///<code>///observed. Someevent + = WEAKEVENTHANDLERFACTORY.MAKEWEAK2 (///Observer.   
 Someeventhandler, observed, "someevent"); </code>///The second parameter of Makeweak removes the weak listener from the event source.    
 Even if you specify///as null for the second parameter, the Observer object is not blocked from being garbage collected, but a reference to a lightweight///object will always remain in the event source. </summary> public static class Weakeventhandlerfactory {///<summary>///we are in make   
     The weak method uses reflection to create an instance of Weakeventhandler, so in (1)///processing cannot specify a generic parameter T to complete the conversion, which is used to simplify this step. </summary>///<typeparam name= "E "> event parameter type. </typeparam> private interface iweakeventhandler<e> where E:eventargs {///<   
         Summary>///event handler.   
         </summary> eventhandler<e> Handler {get;   
     }///<summary>///creates a weak listener for the specified event-handler function. </summary>///<typeparam name= "E" > event parameter type. </typeparam>///<param name= "handler" > Wrapped event handler. </param>///<param name= "Unregister" > a delegate that is used to remove a weak listener from the event source. You can refer to///as NULL, when the event source always keeps a reference to a lightweight object, but does not prevent the objects that are loaded by the package///from being garbage collected. </param>///<param name= "param" > The extra parameters that are used when invoking unregister, can be null. </param>///<returns> generated weak listeners.   
         </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   
         "); The var type = typeof (Weakeventhandler<,>). MakeGenericType (handler.   
        
         Method.declaringtype, typeof (E)); var wehconstructor = type. GetConstructor (new[] {typeof (Eventhandler<e>), typeof (Unregistercall   
        
         back<e>), typeof (Object)}); (1) var weak = (iweakeventhandler<e>) wehconstructor.invoke (new [] {handler, Unregis   
         ter, param}); return weak.   
     Handler;   
     ///<summary>///This method is equivalent to 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>///Registers the listener in the form of a createunregistercallback to create a cancellation of the weak listener delegate. </summary>///<typeparam name= "E" > event parameter type. </typeparam>///<param name= "handler" > Wrapped event handler. </param>///<param name= "observed" > the object being monitored. </param>///<param name= "EventName" > The event name being monitored. </param>///<returns> generated weak listeners.   
         </returns> public static eventhandler<e> makeweak2<e> (eventhandler<e> handler, Object observed, String eventName) where E:eventargs {return makeweak (handler, createunregistercal   
     Lback<e> (observed, eventName)); }   
        
     /// &Lt;summary>///Create a delegate to remove the weak listener registration. </summary>///<typeparam name= "E" > event parameter type. </typeparam>///<param name= "observed" > the object being monitored. </param>///<param name= "EventName" > The event name being monitored. </param>///<returns> Create results, will not be null. </returns> public static unregistercallback<e> createunregistercallback<e> (Object o bserved, String eventName) where E:eventargs {return new unregisterhelper<e> (observed, EVENTN AME).   
     Callback; ///<summary>///helper Classes for removing weak listeners from the event source, in languages such as C++/CLI, which do not support lambda representations///and automatic delegates, use the language of the weak listener   
     The method may be complex, which is used to simplify this///situation. </summary>///<typeparam name= "E" > Delegate event parameter type. </typeparam> Private class unregisterhelper<e> where E:eventargs {///<summa   
         Ry>///the object being monitored.   
       </summary>  Private ReadOnly object observed;   
         <summary>///event name.   
        
         </summary> private readonly string eventName;   
         <summary>///Constructor.   
             </summary> internal Unregisterhelper (object observed, string eventName) {   
             This.observed = observed;   
         This.eventname = EventName;   
         ///<summary>///is used to cancel the listener's delegate.   
             </summary> internal unregistercallback<e> Callback {get {return (handler, param) => {var info = Observ Ed. GetType ().   
                     GetEvent (EventName); Info.   
                 removeEventHandler (observed, handler);   
             }; }}///<summary>///weak event listener. </summary>///<typeparam name= "T" > Listener type. </typeparam>///<typeparam name= "E" > event parameter type. </typeparam> Private Class Weakeventhandler<t, e>: iweakeventhandler<e> where t:c   
         Lass where E:eventargs {///<summary>///a weak reference to the listener.   
        
         </summary> private readonly weakreference weakreference;   
         <summary>///is used to invoke the delegate of the wrapped listener.   
        
         </summary> private readonly Openeventhandler Openhandler;   
         <summary>///Additional parameters when calling unregister.   
        
         </summary> private ReadOnly object param;   
         <summary>///the listener to remove the delegate.   
        
         </summary> private unregistercallback<e> unregister;   
    <summary>///Constructor.     </summary>///<param name= "handler" > Wrapped event handler. </param>///<param name= "unregister" > code for removing weak listeners. </param>///<param name= "param" > Additional parameters when calling unregister. </param> public Weakeventhandler (eventhandler<e> handler, unregistercallback<e& Gt 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;   
         The open delegate type for the///<summary>///wrapper Listener event handler function.   
        
         </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>///Weak listener event handler function. </summary>///<param name= "Sender" > The object that raised the event. </param>///<param name= "E" > Event parameters. </param> private void Invoke (object sender, E e) {T target = (t) weakreferen Ce.   
             Target;   
             if (target!= null) {Openhandler.invoke (target, sender, E);   
                 else if (unregister!= null) {unregister (Handler, param);   
             Unregister = null; }   
         }   
     }   
 }

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.