23

私の理解は、C# 仕様に記載されている動作をサポートするこの長いが素晴らしい記事に基づいています。

CLI 標準 (EMCA-335) は、適切なキャッチがない場合、ランタイムはすぐに終了する必要があることを示しています。.NET ランタイムはこれを行いません。代わりに、C# 仕様 (EMCA-334) の動作に傾いているようです。

まず、言語仕様がフレームワークの動作を定義しているように見えるのは奇妙だと思います。第二に、彼らは矛盾しているようです。

  • それらは互いに矛盾していますか、それともドキュメントの意味を間違っていますか?
  • ランタイムは、標準に準拠するためにこの方法で例外処理を行う必要がありますか?

オプションの質問として、どれが「正しい」ものであるか、つまり、CLI の独自の実装を作成する場合、どれを使用すればよいですか? EMCA-335 (CLI) ドキュメントは 2 か月前に更新され、EMCA-334 (C#) は 2006 年に更新されたことに注意してください。


ECMA-335 パーティション I セクション 12.4.2.5

  • 例外が発生すると、CLI はアレイ内で最初の保護ブロックを検索します。
    • 現在の命令ポインターを含む領域を保護し、
    • キャッチ ハンドラ ブロックであり、
    • 例外を処理するフィルター
  • 現在のメソッドで一致が見つからない場合は、呼び出し元のメソッドが検索されます。一致するものが見つからない場合、CLI はスタック トレースをダンプし、プログラムを中止します。

  • 一致が見つかった場合、CLI はスタックを直前のポイントに戻しますが、今回は finally ハンドラーと fault ハンドラーを呼び出します。次に、対応する例外ハンドラを開始します。

C# 仕様 §15.9.5 および §15.10 ( MSDN の §8.9.5 および §8.10 )

それと CLI 標準との主な違いは、catch ブロックが見つかったかどうかにかかわらず、アプリケーションは存在するだけでなく、スタックをアンワインドし、finally ハンドラーを処理することです。

以下は非常に大まかな要約であるため、これをよりよく理解するために標準自体を読むことをお勧めします。考えられる各シナリオで try ステートメントを実行する方法を段階的に概説します。

  • 例外を発生させる関数で:
    • 各 try ステートメントで一致する catch 句を探します
      • 存在する場合は catch ステートメントを実行します
    • finally ブロックが存在する場合は実行されます
  • ハンドラーが存在しない場合は、呼び出し元の関数で上記の手順が繰り返されます。
  • 例外処理が現在のスレッドのすべての関数メンバー呼び出しを終了し、スレッドに例外のハンドラーがないことを示す場合、スレッド自体が終了します。このような終了の影響は実装定義です。
4

3 に答える 3

5

ここには紛争はありません。C# 言語仕様は、次のように表現されています。

try ステートメントに catch 句がない場合、または例外に一致する catch 句がない
場合: • try ステートメントに finally ブロックがある場合、finally ブロックが実行されます。
• 例外は、次の外側の try ステートメントに伝達されます。

ここの箇条書き 2では、次に囲む try ステートメントがない場合に何が起こるかを特に述べていません。そのためには、8.9.5 の最後を参照してください。

例外処理が現在のスレッドのすべての関数メンバー呼び出しを終了し、スレッドに例外のハンドラーがないことを示す場合、スレッド自体が終了します。このような終了の影響は実装定義です。

それは確かに実装定義です。Ecma 335 仕様を超えて、例外処理ポリシーは Microsoft CLR で構成可能な項目です。ICLRPolicyManager::SetActionOnFailure() によって制御されます。<legacyUnhandledExceptionPolicy>app.exe.config ファイル要素を使用して、既定のホストで構成可能です。CLR バージョン 2.0 以降の既定では、プログラムはすぐに終了します。

そうでなければ、これはかなり非生産的な聖書の解釈学です。これは、C# プログラマーにとって驚くべきことではありません。特に、テストがいかに簡単かを考えるとそうです。

于 2012-08-29T00:13:33.960 に答える
3

これは漠然とした言い回しの問題かもしれないと思います。

現在のメソッドで一致が見つからない場合は、呼び出し元のメソッドが検索されます。一致するものが見つからない場合、CLI はスタック トレースをダンプし、プログラムを中止します。

わかりました、それは C# に当てはまります。を持っていない場合catch、例外によってプログラムが停止することは誰もが知っています。

一致が見つかった場合、CLI はスタックを直前のポイントに戻しますが、今回は finally ハンドラーと fault ハンドラーを呼び出します。次に、対応する例外ハンドラを開始します。

これは、C# からわかっていることとも一致します。スローされた例外からブロックまでスタックを上っていくときに、処理するブロックがいくつかある場合finally(表示されません) 、それらは処理されますが、そこで停止し、それ以上スタックを上ることはありません。faultcatch

先ほど引用した 2 番目の抜粋を開始する「If」をどのように読むかについては、多くのことがかかっています。あなたはそれを「if ... then ... そうでなければそんなことはない」と読んでいます。ただし、これはスタック内のウォーク先のポイントを特定する最初の抜粋として読むことができますcatch。キャッチがない場合は、スタックの一番上に移動し、ダンプを取得して中止します。finally ハンドラー (およびフォルト ハンドラー) は引き続き呼び出されますが、ポイントは一致する catch ハンドラーではありません。

あなたの読書は最も文字通りであり、私のものは物事を少し拡張したものです. finallyただし、私のものは、同じ標準の他の場所の説明と最もよく一致しています。

于 2012-08-29T00:26:28.880 に答える
0

OPで引用された記事には、誤った基本的な仮定があります。

もちろん、最初にWindows構造化例外処理(SEH)を考慮せずに、管理された例外について話すことはできません。また、C++例外モデルも確認する必要があります。これは、マネージ例外とC ++例外の両方が基盤となるSEHメカニズムの上に実装されており、マネージ例外はSEHとC++の両方の例外と相互運用する必要があるためです。

CLR標準(ISO 23271 / ECMA 335)は、意図的にプラットフォームに依存しません。Microsoftの実装は、考えられる多くの実装の1つです(もちろん、Monoは別の実装です)。

Windowsの構造化例外処理およびC++例外処理との相互運用性は、確かにMicrosoftの選択であり、ISO23271の要件ではありません。

于 2012-08-29T02:38:04.163 に答える