15

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)
    }

それで、アイデアや回避策はありますか??

4

7 に答える 7

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);
    }
    
  2. この場合、メイン クラスを破棄するときにすべてのクライアントを破棄する必要があります。

    protected override Dispose(bool disposing)
    {
        foreach (PreloadClient client in _activeClients)
        { 
            client.PreloadCompleted -= client_PreloadCompleted;
            client.Dispose();
        }
        _activeClients.Clear();
        base.Dispose(disposing);
    }
    
  3. この実装はスレッドセーフではないことに注意してください

    • メソッドが別のスレッドから呼び出されるため、_activeClientsリストへのアクセスはスレッドセーフにする必要がありますPreloadCompleted
    • 含まれているオブジェクトは、クライアントがイベントを発生させる前に破棄される場合があります。その場合、"do stuff" は何もしないはずなので、これはもう 1 つの注意事項です。
    • tryイベント ハンドラー内で/finallyブロックを使用して、すべての場合にオブジェクトが確実に破棄されるようにすることをお勧めします。
于 2009-06-10T12:05:08.283 に答える
3

コールバックでクライアントを破棄しないのはなぜですか?

于 2009-06-10T11:13:29.743 に答える
1

私にはいくつかのアイデアがあります:

  1. アーキテクチャを変更します。
  2. ハンドラーで破棄する
  3. EventWaitHandle を使用する
于 2009-06-10T11:12:48.030 に答える
0

登録されているイベント ハンドラーがある場合、そのオブジェクトに対して呼び出すことができるイベントがある間は、オブジェクトを実際に破棄することはできません。あなたの最善の策は、包含クラスを使い捨てにして、クライアントをクラス変数に格納し、包含クラスが破棄されたときに破棄することです。

何かのようなもの

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();
    }
}
于 2009-06-10T11:14:32.627 に答える
0

オブジェクトの破棄は、GC が (最終的に) 来てオブジェクトを収集するまで保持したくないリソースを削除するために使用されます。dispose メソッドで必要なものを殺しますclient_PreloadCompletedか?

予想されるすべてのコールバックが発生したときに、オブジェクトにそれ自体を破棄させることができます。予想されるコールバックごとに「参照カウンター」を保持し、発生するコールバックごとにそれを減らします-コールバックハンドラーの最後でnullをチェックし、そうであれば破棄します。

その他の回避策: 心配する必要はありませんIDisposable。GC がオブジェクトを収集します。おそらく、コールバック ハンドラー (起動されない可能性がある) が重大な状態になることは望ましくありません。それ(コールバック)は、呼び出されたときに必要なリソースを開き、その後閉じます。

于 2009-06-10T11:15:35.310 に答える
0

非同期待機と決定論的破棄はうまく組み合わせられません。使い捨てのものをあるクラスに入れ、イベントを別のクラスに入れるようにコードを分割する方法を見つけることができれば、すべてが簡単になります。

于 2009-06-10T11:21:56.357 に答える
0

client_PreloadCompletedメソッドで破棄しないのはなぜですか?Disposeクライアントオブジェクト内から必要なすべてのデータにアクセスした後、上記のメソッド内で呼び出すだけで、thecoop が提供するものと同様です。

編集: orialmog も同様に提供したと思います。

于 2009-06-10T11:30:11.037 に答える