What best practices for cleaning up event handler references?

后端 未结 6 1642
一个人的身影
一个人的身影 2020-12-04 15:52

Often I find myself writing code like this:

        if (Session != null)
        {
            Session.KillAllProcesses();
            Session.AllUnitsReady          


        
6条回答
  •  执念已碎
    2020-12-04 16:23

    The event-handling pattern that's automatically generated using the vb.net WithEvents keyword is a pretty decent one. The VB code (roughly):

    WithEvents myPort As SerialPort
    
    Sub GotData(Sender As Object, e as DataReceivedEventArgs) Handles myPort.DataReceived
    Sub SawPinChange(Sender As Object, e as PinChangedEventArgs) Handles myPort.PinChanged
    

    will get translated into the equivalent of:

    SerialPort _myPort;
    SerialPort myPort
    {  get { return _myPort; }
       set {
          if (_myPort != null)
          {
            _myPort.DataReceived -= GotData;
            _myPort.PinChanged -= SawPinChange;
          }
          _myPort = value;
          if (_myPort != null)
          {
            _myPort.DataReceived += GotData;
            _myPort.PinChanged += SawPinChange;
          }
       }
    }
    

    This is a reasonable pattern to follow; if you use this pattern, then in Dispose you would set to null all properties that have associated events, which will in turn take care of unsubscribing them.

    If one wanted to automate disposal slightly, so as to ensure that things got disposed, one could change the property to look like this:

    Action myCleanups; // Just once for the whole class
    SerialPort _myPort;
    static void cancel_myPort(myType x) {x.myPort = null;}
    SerialPort myPort
    {  get { return _myPort; }
       set {
          if (_myPort != null)
          {
            _myPort.DataReceived -= GotData;
            _myPort.PinChanged -= SawPinChange;
            myCleanups -= cancel_myPort;
          }
          _myPort = value;
          if (_myPort != null)
          {
            myCleanups += cancel_myPort;
            _myPort.DataReceived += GotData;
            _myPort.PinChanged += SawPinChange;
          }
       }
    }
    // Later on, in Dispose...
      myCleanups(this);  // Perform enqueued cleanups
    

    Note that hooking static delegates to myCleanups means that even if there are many instances of myClass, there will only have to be one copy of each delegate system-wide. Perhaps not a big deal for classes with few instances, but potentially significant if a class will be instantiated many thousands of times.

提交回复
热议问题