この質問は、以前は.NET 4.0で機能していたコードが、.NET 4.5では未処理の例外で失敗したために発生しました。これは、一部はtry/finallyが原因です。詳細が必要な場合は、 Microsoftconnectで詳細をお読みください。この例のベースとして使用したので、参照すると役立つ場合があります。
コード
この質問の背後にある詳細について読まないことを選択した人々のために、これが起こった状況を非常に簡単に見てみましょう。
using(var ms = new MemoryStream(encryptedData))
using(var cryptoStream = new CryptoStream(encryptedData, decryptor, CryptoStreamMode.Read))
using(var sr = new StreamReader(cryptoStream))
Dispose
この問題は、CryptoStreamのメソッドからスローされる例外があることです(これらはusingステートメント内にあるため、これらの例外は2つの異なるfinallyブロックからスローされます)。cryptoStream.Dispose()
によって呼び出されると、StreamReader
がCryptographicException
スローされます。2回目cryptoStream.Dispose()
は、usingステートメントで呼び出され、ArgumentNullException
次のコードは、上記のリンクから不要なコードのほとんどを削除し、usingステートメントをtry / finalsにアンワインドして、finallyブロックにスローされていることを明確に示します。
using System;
using System.Security.Cryptography;
namespace Sandbox
{
public class Program
{
public static void Main(string[] args)
{
try
{
try
{
try
{
Console.WriteLine("Propagate, my children");
}
finally
{
// F1
Console.WriteLine("Throwing CryptographicExecption");
throw new CryptographicException();
}
}
finally
{
// F2
Console.WriteLine("Throwing ArgumentException");
throw new ArgumentException();
}
}
catch (ArgumentException)
{
// C1
Console.WriteLine("Caught ArgumentException");
}
// Same behavior if this was in an enclosing try/catch
catch (CryptographicException)
{
// C2
Console.WriteLine("Caught CryptographicException");
}
Console.WriteLine("Made it out of the exception minefield");
}
}}
注:try / finalは、参照されたコードの拡張されたusingステートメントに対応します。
出力:
伝播する、私の子供たち CryptographicExecptionを投げる ArgumentExceptionをスローします ArgumentExceptionをキャッチしました 何かキーを押すと続行します 。。。
CryptographicException
catchブロックが実行されたことはないようです。ただし、そのcatchブロックを削除すると、例外によってランタイムが終了します。
もう少し情報
編集:これは仕様の最新リビジョンに更新されました。私がたまたまMSDNから入手したものは、古い表現でした。 Lost
に更新されましたterminated
。
C#仕様の詳細については、セクション8.9.5および8.10で例外の動作について説明しています。
- finallyブロック内を含め、例外がスローされると、制御は、それを囲むtryステートメントの最初のcatch節に移されます。これは、適切なステートメントが見つかるまでtryステートメントを続けます。
- finallyブロックの実行中に例外がスローされ、例外がすでに伝播されていた場合、その例外は終了します。
「終了」は、最初の例外が2番目にスローされた例外によって永久に隠されているように見えますが、何が起こっているのかはわかりません。
質問はここのどこかにあると確信しています
ほとんどの場合、ランタイムが実行していることを視覚化するのは簡単です。F1
コードは、例外がスローされる最初のfinallyブロック()まで実行されます。例外が伝播すると、2番目のfinallyブロック(F2
)から2番目の例外がスローされます。
仕様によると、CryptographicException
スローされたfromF1
は終了し、ランタイムはのハンドラーを探していますArgumentException
。ランタイムはハンドラーを見つけ、ArgumentException
(C1
)のcatchブロック内のコードを実行します。
ここで霧が発生します。仕様では、最初の例外が終了することが示されています。ただし、2番目のcatchブロック(C2
)がコードから削除された場合、CryptographicException
失われたと思われるものは、プログラムを終了する未処理の例外になります。現在のところ、C2
コードは未処理の例外で終了しないため、表面的には例外を処理しているように見えますが、ブロック内の実際の例外処理コードは実行されません。
質問
質問は基本的に同じですが、具体性のために言い換えられています。
ブロックを削除すると例外が処理されずにランタイムが終了するため、finallyブロックを囲むことからスローされ
CryptographicException
た例外が原因でが終了するのはどうしてですか?ArgumentException
catch (CryptographicException)
CryptographicException
ブロックが存在するときにランタイムが処理しているように見えるのにcatch (CryptographicException)
、ブロック内のコードが実行されないのはなぜですか?
追加情報編集
私はまだこれの実際の振る舞いを調査しています、そして答えの多くは少なくとも上記の質問の一部に答えるのに特に役立ちました。
catch (CryptographicException)
ブロックをコメントアウトした状態でコードを実行すると発生するもう1つの奇妙な動作は、.NET4.5と.NET3.5の違いです。.NET 4.5は、をスローしCryptographicException
てアプリケーションを終了します。ただし、.NET 3.5は、例外があるC#仕様に従って動作するようです。
伝播する、私の子供たち CryptographicExecptionを投げる 未処理の例外:System.Security.Cryptography.CryptographicException [...] ram.cs:23行目 ArgumentExceptionをスローします ArgumentExceptionをキャッチしました 例外的な地雷原からそれを作りました
.NET 3.5では、仕様で読んだ内容がわかります。キャッチする必要があるのは。だけなので、例外は「失われた」または「終了した」になりますArgumentException
。そのため、プログラムは実行を継続できます。私のマシンには.NET4.5しかありませんが、これは.NET 4.0で発生するのでしょうか?