8

クラスにソケットとイベントが含まれている場合に Dispose パターンを実装する方法は?

それはこのようなものであるべきですか?

class MyClass
{
   Socket m_ListenerSocket = new Socket();
   book m_Disposed=false;

   public void Dispose()
   {
      Dispose(true);
      GC.SuppressFinalize(this);
   }

   private void Dispose(bool isDisposing)
   {
      if (!m_Disposed)
      {
          if (isDisposing)
          {
              if (m_ListenerSocket != null)
              {
                   m_ListenerSocket.Dispose();
                   innerClass.Notify -= Notify;
              }
          }
        //finalized unmanged code here
        m_Disposed = true;
      }
  }

  ~MyClass()
  {
       Dispose(false);
  }
}

私は混乱しています...ソケットクラスは「winSockのマネージコードc#バージョン」ですか?したがって、ユーザーが dispose と呼ばれる場合 (「isDisposing IS true」) に解放する必要があります。イベント ハンドラーはどうですか?

完成したコメント セクションでは、Inptr オブジェクトのみを解放する必要がありますか? ありがとう。

4

4 に答える 4

3

イベントの有無にかかわらず、使い捨てのオブジェクトを扱う方法はたくさんあると思います。

単なる推測ですが、.net Frameworkからクラスを取得し、このクラスにDispose()メソッドがある場合、それはマネージコードであるとほぼ言えます。したがって、代わりにDisposeメソッドを呼び出すだけで安全です。自分でデストラクタを作成します。以下の私の例に見られるように、IDisposableインターフェースを独自のクラスに実装してから、内部オブジェクトを適切な方法で破棄することもできるため、これはかなり偏ったものです。

これはあなたに役立ちますか?

public class MyClassWithSocket :IDisposable 
{

    Socket myInternalSocket = null;

    public void methodThatUsesSocket()
    {
        using (var mySocket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream , ProtocolType.Tcp))
        {
        //do something with socket 
        //this will be disposed automatically

        }
    }

    public void methodThatUsesInternalSocket() 
    {
        myInternalSocket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
        //do other things
    }

    public static Socket SomethingThatReturnsSocket()
    {

        Socket tempSocket =  new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);

        return tempSocket;
    }


    public void Dispose()
    {
        myInternalSocket.Dispose();
    }
}
于 2012-11-13T07:43:15.660 に答える
2

Socket はマネージ クラスであるため、実装のガイドラインではIDisposable、ファイナライザーは不要であると規定されています。実際、ファイナライザーを使用すると、オブジェクトのガベージ コレクションが実際に遅延します。これは、最初のガベージ コレクション中にファイナライザーが呼び出され、2 回目のガベージ コレクションの実行時にオブジェクトがガベージ コレクションされるためです。

イベントに関しては、innerClass オブジェクトが短命でない限り、Disposeイベント サブスクリプションによってinnerClassのインスタンスへの参照が保持されるため、おそらくメソッド内のイベントから登録解除する必要があります。イベントと Dispose の詳細については、この質問MyClassを参照してください。

あなたのシナリオには、次の実装で十分だと思います。

class MyClass : IDisposable
{
   Socket m_listenerSocket = new Socket();

   public void Dispose()
   {
       m_listenerSocket.Dispose();
       innerClass.Notify -= Notify; 
   }
}

「ファイナライズされたアンマネージ コードをここに」とコメントしたコードの部分は、IntPtrなどの形式のハンドルなど、アンマネージ リソースのみを解放SafeHandleする必要があります。でラップして、管理対象リソースとして扱うことができIntPtrますSafeHandle

于 2012-11-13T10:28:27.167 に答える
1

何事も無言にさせてはならない。

私の経験では、広く使用されている「ソフト エラー」 Dispose(disposing)メカニズムはよく考えられていません。私は「ハードエラー」の方が好きです。

実装するオブジェクトを作成するときは、通常、次のことを行うクラスをDispose()拡張します。MyDisposable#if DEBUG

  1. そのコンストラクターは、現在のスタック トレースをキャプチャし、後で使用できるように保存します。(注: これは非常に遅いです。Microsoft だけがその理由を知っています。)
  2. クラスには、 にbool disposed初期化されたメンバーが含まれていますfalse
  3. Dispose() オブジェクトがまだ破棄されていないことをアサートし、オブジェクトを破棄済みとしてマークします。
  4. オブジェクトのデストラクタ (ファイナライズ時に呼び出される) は、オブジェクトが破棄されているかどうかを確認し、破棄されていない場合は、作成中に記録されたスタック トレースをダンプします。これにより、破棄可能なオブジェクトを割り当てたが、破棄するのを忘れたソース コード内の正確な場所を見つけることができます。

また、から派生したオブジェクトは、MyDisposable通常、すべてのメソッド、さらにはすべてのゲッターで前提条件としてassertします。 !disposed

上記により、次のことが保証されます。

  1. オブジェクトを破棄できる方法は 1 つだけです。
  2. 各使い捨てオブジェクトは一度だけ破棄されます。
  3. オブジェクトが破棄されると、破棄可能なオブジェクトのメソッドは呼び出されません。
  4. 使い捨てオブジェクトを破棄するのを忘れた場合は、見つけて、それがどこに割り当てられたかを正確に知ることができます。

言うまでもなく、そうでない場合は#DEBUGMyDisposableパフォーマンスを妨げないように、実質的に何もコンパイルされません。

したがって、 「ソフト エラー」メカニズムを実装するクラスを、最初に 「ハード エラー」Dispose(disposing)メカニズムを実装するクラスにラップせずに使用することは (実用的な場合には) 避けようとします。 Dispose()

于 2015-02-17T09:52:42.737 に答える