1

私たちのフレームワークにはいくつかのオブジェクトがあり、要件によりイベント ObjectTerminated を提供する必要があります。フレームワークのユーザーは、このイベントをサブスクライブして、使用している管理されていないものをクリーンアップできます。これらのオブジェクトは、アプリケーションの存続期間全体にわたって存在するように設計されており、私はそれらの存続期間を制御していません。それらはシングルトンの配列と考えることができます。

次のようなコードを書きたい:

class SomeWorkflowControlObject
{
     public event EventHandler<> ObjectTerminated;

     ~SomeWorkflowControlObject()
     {
          if (ObjectTerminated != null) ObjectTerminated(this, null);         
     }
}

よくわかりませんが、それをしてもいいですか。このようなソリューションで何が問題になる可能性がありますか?

更新しました:

Process.GetCurrentProcess().Exited はどうですか? そんな使い方できるの?

4

2 に答える 2

1

あなたはこれをすべきではありません。基本的に、デストラクタはC#には存在しません。あなたが書いたのはファイナライザーであり、ファイナライザーが行うべき唯一のことは、管理されていないリソースを解放することです。

ガベージコレクタがすでにオブジェクトを削除している可能性があるため、他の管理対象オブジェクトにアクセスすることはまったく許可されていません。null私はあなたのチェックがこの状況に対する十分な防御ではないと思います。そのオブジェクト参照は、すでになくなっていても、(イベント)デリゲートを指している可能性があります。

つまり、これを行わないでください。

代替案:

  1. Windowsフォームアプリケーションを使用している場合は、Application.ApplicationExitイベントをサブスクライブします。

  2. IDisposable代わりにインターフェースの実装を検討してから、次のようなことを行うことをお勧めします。

    public class SomethingVeryLongLived : IDisposable
    {
        …
    }
    
    …
    
    public static void Main()
    {
        using (var sth = new SomethingVeryLongLived(…))
        {
            Application.Run(new SomeForm(…));
        } // <-- at this point, foo.Dispose() is guaranteed to be called.
    }
    

    を使用する場合でも、IDisposable破棄されたオブジェクトにアクセスする必要がなくなるため、破棄されるオブジェクト内でイベントをトリガーすることはおそらく良い考え/設計ではないことに注意してください。

    このため、次のことをお勧めします。

  3. try…finallyブロックを使用する

    public static void Main()
    {
        var sth = new SomethingVeryLongLived(…);
        try
        {
            Application.Run(new SomeForm(…));
        }
        finally
        {
            SomethingVeryLongLived.Terminate();
        }
    }
    

    あなたがインターフェースを悪用してIDisposableいないので、これは私にとって最良のように思えます、そしてそれはコードが何をするかを非常に明確にしています...隠された意味はありません。

于 2012-07-06T12:47:35.550 に答える
1

そのフレームワークの設計には本質的に欠陥があると思います。説明させてください:

1. [...]フレームワーク内のいくつかのオブジェクト。要件により、 event を提供する必要がありますObjectTerminated

これは意味がありません。イベントの名前が示すように、オブジェクトが終了した場合、そのオブジェクトは既になくなっており、アクセスできなくなっていると想定します。これにより、次の 2 つの疑問が生じます。

  • 死んだものはどのようにイベントを引き起こしますか? それは死体が墓からあなたに話しかけているようなものです。「私は死んでいます」。本当にこれが欲しいですか?

  • イベント送信者がもはやそこにいるはずがないのに、なぜ他の誰かがそのようなイベントに反応することに興味を持つのでしょうか? 死体がすでに埋葬された後、何を片付ける必要がありますか?

2. 私は彼らの生活をコントロールしていません。

では、誰彼らの寿命をコントロールしているのでしょうか? 適切なタイミングで必要なクリーンアップ作業を行う、またはトリガーすることが彼らの責任ではないのはなぜですか? この点についてさらに詳しく説明しましょう。

3. [...] このイベントにサブスクライブして、管理されていないものをクリーンアップできます [...]

この管理されていないものはどこにあり、どのオブジェクトがそれを処理する責任がありますか? それがあなた自身のオブジェクトである場合、なぜあなたのオブジェクトはそれを処分しないのですか? 代わりに、他の誰かが物を処分できるように、代わりにイベントをトリガーしたいのはなぜですか? 隣人が自分でゴミを片付けるのではなく、私が隣人のゴミを片付けるようなものです。(私はそこでおばあさんについて話しているのではありません。)

あなたのクラスは、次のようになれば、より意味のあるものになります:

class SomeWorkflowControlObject : IDisposable
{
     // the following event doesn't make sense, sorry.
     // public event EventHandler<> ObjectTerminated;

     private IntPtr _handleToUnmanagedResource;

     ~SomeWorkflowControlObject()
     {
         Dispose(explicitly: false);         
     }

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

     protected virtual void Dispose(bool explicitly)
     {
         if (explicitly)
         {
             // free managed resources here; perhaps trigger an event 'Disposing'.
         }
         DisposeUnmanagedResource(_handleToUnmanagedResource);
     }
}

つまり、それは管理されていないリソースのラッパーであり、その処分についてはそれ自体が責任を負い、他の誰にも責任はありません。したがって、他の誰かが管理されていないリソースを処分できるように、イベントをトリガーする必要はなくなりました。

于 2012-07-06T13:50:31.377 に答える