2

特定の状況下で、次のようなクラスのすべての例外を処理するにはどうすればよいですか?

class Test : IDisposable {
  public Test() {
    throw new Exception("Exception in ctor");  
  }
  public void Dispose() {
    throw new Exception("Exception in Dispose()");
  }
  ~Test() {
    this.Dispose();
  }
}

私はこれを試しましたが、うまくいきません:

static void Main() {
  Test t = null;
  try {
    t = new Test();
  }
  catch (Exception ex) {
    Console.Error.WriteLine(ex.Message);
  }

  // t is still null
}

「using」も使用しようとしましたが、~Test(); からスローされた例外を処理しません。

static void Main() {
  try {
    using (Test t = new Test()) { }
  }
  catch (Exception ex) {
    Console.Error.WriteLine(ex.Message);
  }
}

どうすれば回避できますか?

4

3 に答える 3

5

まず、ファイナライザーは決して例外をスローすべきではありません。もしそうなら、何か壊滅的な問題が発生しており、アプリは激しくクラッシュするはずです. また、ファイナライザーは Dispose() を直接呼び出すべきではありません。ファイナライザーが実行されると、マネージド リソースは有効な状態にさえならない可能性があるため、ファイナライザーはアンマネージド リソースを解放するためだけのものです。管理された参照はガベージ コレクターによって既にクリーンアップされているため、ファイナライザーではなく、Dispose でそれらを破棄するだけで済みます。

つまり、Dispose を明示的に呼び出すと、Dispose の例外がキャッチされるはずです。「using」ケースで例外がスローされなかった理由がよくわかりません。そうは言っても、回避できるのであれば、 Dispose も例外をスローするべきではありません。特に、using ブロックの後に例外をスローする Dispose は、using ブロック内で発生する可能性があるすべての例外を Dispose 例外で「上書き」します。


追加の参考資料はこちら

于 2010-04-20T01:24:12.990 に答える
3

答えの一部は、これらの場合に例外を処理するべきではないということだと思います。

例外から回復できる場合、または例外に追加情報を追加して再スローできる場合にのみ、例外をキャッチする必要があります。すべての例外をキャッチする必要はありません。コール スタックの上位にあるコードで、できるだけ多くの例外を処理できるようにします。

于 2010-04-20T01:30:29.223 に答える
1

いくつかの観察があります。

まず、Dispose から例外をスローしないようにします。実際、私は決して言わないところまで行きます。.NET 開発者は、正当な理由により、Dispose が常に成功することを期待するように条件付けられてきました。呼び出しを毎回 try-catch でラップするのは厄介であり、読みやすさが確実に低下します。

第二に、これは頻繁に議論される問題ですが、コンストラクターから例外をスローしないようにします。ArgumentException や IndexOutOfRangeException などの状態の検証に関連する例外は、通常、事前条件違反のために生成され、通常はプログラミング エラーの結果であるため、問題ありません。ただし、SqlException などの予測不可能な例外は、呼び出し元がコンストラクターを try-catch ブロックにラップすることをほとんど強制します。繰り返しますが、これは厄介なコーディング シナリオにつながります。しかし、さらに重要なことに、コンストラクターがアンマネージ リソースを割り当て、呼び出し元に新しいインスタンスを返す前に例外をスローするシナリオでは、これが微妙なリソース リークにつながる可能性があります。インスタンス参照がなければ、呼び出し元は Dispose を呼び出すことができません。

于 2010-04-20T02:35:01.990 に答える