How to dispose objects having asynchronous methods called?

后端 未结 7 2144
再見小時候
再見小時候 2020-12-18 21:34

I have this object PreloadClient which implements IDisposable, I want to dispose it, but after the asynchronous methods finish their call... which

相关标签:
7条回答
  • 2020-12-18 22:17

    Why not disposing in the client_PreloadCompleted method? Similar to what thecoop offered, just with the Dispose call inside the above method, after you have accessed all the needed data from inside the client object.

    Edit: I think that is what orialmog offered as well.

    0 讨论(0)
  • 2020-12-18 22:24

    If there are event handlers being registered, you can't really dispose the object while there are events that could be called on it. Your best bet is to make the containing class disposable & store the client in a class variable, to be disposed when the containing class is.

    Something like

    class ContainingClass : IDisposable
    {
        private PreloadClient m_Client;
    
        private void Preload(SlideHandler slide)
        {
             m_Client = new PreloadClient())
    
             m_Client.PreloadCompleted += client_PreloadCompleted;
             m_Client.Preload(slide);
    
        }
        private void client_PreloadCompleted(object sender, SlidePreloadCompletedEventArgs e)
        {
        }
    
        public void Dispose()
        {
            if (m_Client != null)
                m_Client.Dispose();
        }
    }
    
    0 讨论(0)
  • 2020-12-18 22:24

    Asynchronous waits and deterministic disposal don't mix very well. If you can find a way of splitting the code such that the disposable stuff goes in one class and the events go in another, that would make everything simpler.

    0 讨论(0)
  • 2020-12-18 22:25

    Why not dispose the client in the callback?

    0 讨论(0)
  • 2020-12-18 22:29
    1. You shouldn't use the using construct, but rather dispose your objects when they are no longer needed:

      // keep a list of strong references to avoid garbage collection,
      // and dispose them all in case we're disposing the encapsulating object
      private readonly List<PreloadClient> _activeClients = new List<PreloadClient>();
      private void Preload(SlideHandler slide)
      {
          PreloadClient client = new PreloadClient();
          _activeClients.Add(client);
          client.PreloadCompleted += client_PreloadCompleted;
          client.Preload(slide);
      }
      
      private void client_PreloadCompleted(object sender,
           SlidePreloadCompletedEventArgs e)
      {
          PreloadClient client = sender as PreloadClient;
      
          // do stuff
      
          client.PreloadCompleted -= client_PreloadCompleted;
          client.Dispose();
          _activeClients.Remove(client);
      }
      
    2. in this case, you have to dispose all clients when disposing the main class:

      protected override Dispose(bool disposing)
      {
          foreach (PreloadClient client in _activeClients)
          { 
              client.PreloadCompleted -= client_PreloadCompleted;
              client.Dispose();
          }
          _activeClients.Clear();
          base.Dispose(disposing);
      }
      
    3. Note that this implementation is not thread safe

      • Access to the _activeClients list must be made thread-safe, as your PreloadCompleted method is called from a different thread
      • Your containing object may be disposed before a client fires the event. In that case "do stuff" should do nothing, so this is another thing you should take care of.
      • It might be a good idea to use a try/finally block inside your event handler, to make sure that the object gets disposed in all cases
    0 讨论(0)
  • 2020-12-18 22:37

    I have a few ideas:

    1. change your architecture.
    2. dispose in the handler
    3. use EventWaitHandle
    0 讨论(0)
提交回复
热议问题