如何处理具有异步方法的对象?

Jal*_*aer 14 .net c# dispose asynchronous idisposable

我有这个PreloadClient实现的对象IDisposable,我想处理它,但在异步方法完成它们的调用之后......这没有发生

    private void Preload(SlideHandler slide)
    {
        using(PreloadClient client = new PreloadClient())
        {                 
             client.PreloadCompleted += client_PreloadCompleted;
             client.Preload(slide);
        }
        // Here client is disposed immediately
    }
    private void client_PreloadCompleted(object sender, SlidePreloadCompletedEventArgs e)
    {
     // this is method is called after a while, 
     // but errors are thrown when trying to access object state (fields, properties)
    }
Run Code Online (Sandbox Code Playgroud)

那么,任何想法或工作?

Gro*_*roo 11

  1. 您不应该使用该using构造,而是在不再需要它们时处置它们:

    // 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);
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 在这种情况下,您必须在处置主类时处置所有客户端:

    protected override Dispose(bool disposing)
    {
        foreach (PreloadClient client in _activeClients)
        { 
            client.PreloadCompleted -= client_PreloadCompleted;
            client.Dispose();
        }
        _activeClients.Clear();
        base.Dispose(disposing);
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 请注意,此实现不是线程安全的

    • 访问_activeClients列表必须线程安全的,因为PreloadCompleted从另一个线程调用您的方法
    • 您的包含对象可能会在客户端触发事件之前处理.在这种情况下,"做东西"应该什么都不做,所以这是你应该照顾的另一件事.
    • 在事件处理程序中使用try/ finallyblock 可能是个好主意,以确保在所有情况下都可以处置该对象