サーチ…
備考
関連:
例外をキャッチする
例外的な状況でコードで例外をスローすることができます。これの例としては、
- ストリームの終わりを過ぎて読み取ろうとしています
- ファイルにアクセスするために必要な権限がない
- ゼロで割るなどの無効な操作を実行しようとしています
- インターネットからファイルをダウンロードするときに発生するタイムアウト
呼び出し元は、これらの例外を「キャッチ」することで処理できます。以下の場合にのみ実行してください。
- それは実際に例外的な状況を解決したり、適切に回復することができます。
- 例外を再スローする必要がある場合に有用な例外に追加のコンテキストを提供することができます(再スローされた例外は例外ハンドラによってコールスタックの上位にキャッチされます)
例外をキャッチしないことを選択することは、それがより高いレベルで処理されることが意図されている場合には完全に有効であることに留意されたい。
例外をキャッチするには、潜在的にスローするコードをtry { ... }
ブロックに次のようにラップし、 catch (ExceptionType) { ... }
ブロックで処理できるcatch (ExceptionType) { ... }
ます。
Console.Write("Please enter a filename: ");
string filename = Console.ReadLine();
Stream fileStream;
try
{
fileStream = File.Open(filename);
}
catch (FileNotFoundException)
{
Console.WriteLine("File '{0}' could not be found.", filename);
}
finallyブロックの使用
例外が発生したかどうかに関係なく、 try-finally
またはtry-catch-finally
のfinally { ... }
ブロックは常に実行されます(例外はStackOverflowException
がスローされたか、 Environment.FailFast()
)。
try { ... }
ブロックで取得したリソースを安全に解放またはクリーンアップするために利用できます。
Console.Write("Please enter a filename: ");
string filename = Console.ReadLine();
Stream fileStream = null;
try
{
fileStream = File.Open(filename);
}
catch (FileNotFoundException)
{
Console.WriteLine("File '{0}' could not be found.", filename);
}
finally
{
if (fileStream != null)
{
fileStream.Dispose();
}
}
キャッチされた例外のキャッチと再スロー
例外をキャッチして何かをしたいが、例外のために現在のコードブロックの実行を続行できないときは、コールスタック内の次の例外ハンドラに例外を戻すことが必要な場合があります。これを行うには良い方法と悪い方法があります。
private static void AskTheUltimateQuestion()
{
try
{
var x = 42;
var y = x / (x - x); // will throw a DivideByZeroException
// IMPORTANT NOTE: the error in following string format IS intentional
// and exists to throw an exception to the FormatException catch, below
Console.WriteLine("The secret to life, the universe, and everything is {1}", y);
}
catch (DivideByZeroException)
{
// we do not need a reference to the exception
Console.WriteLine("Dividing by zero would destroy the universe.");
// do this to preserve the stack trace:
throw;
}
catch (FormatException ex)
{
// only do this if you need to change the type of the Exception to be thrown
// and wrap the inner Exception
// remember that the stack trace of the outer Exception will point to the
// next line
// you'll need to examine the InnerException property to get the stack trace
// to the line that actually started the problem
throw new InvalidOperationException("Watch your format string indexes.", ex);
}
catch (Exception ex)
{
Console.WriteLine("Something else horrible happened. The exception: " + ex.Message);
// do not do this, because the stack trace will be changed to point to
// this location instead of the location where the exception
// was originally thrown:
throw ex;
}
}
static void Main()
{
try
{
AskTheUltimateQuestion();
}
catch
{
// choose this kind of catch if you don't need any information about
// the exception that was caught
// this block "eats" all exceptions instead of rethrowing them
}
}
あなたは例外タイプと例外プロパティ(C#6.0の新機能、VB.NETでもう少し利用可能です(引用が必要です))でフィルタリングすることもできます:
例外フィルタ
C#6.0の例外は、 when
演算子を使用してフィルタリングできるためです。
これは単純なif
を使用するのと似ていますが、 when
の条件が満たされていないwhen
はスタックを巻き戻しません。
例
try
{
// ...
}
catch (Exception e) when (e.InnerException != null) // Any condition can go in here.
{
// ...
}
同じ情報はC#6.0の機能にあります: 例外フィルタ
catchブロック内での例外の再試行
catch
ブロック内では、例外値を指定せずにthrow
キーワードを単独で使用することができ、 catch
されたばかりの例外を再現することができます。例外を再発行すると、元の例外は例外処理チェーンを継承し、その呼び出しスタックまたは関連するデータは保持されます。
try {...}
catch (Exception ex) {
// Note: the ex variable is *not* used
throw;
}
一般的なアンチパターンは代わりthrow ex
をthrow ex
することです。スタックトレースの次の例外ハンドラのビューを制限するという効果があります。
try {...}
catch (Exception ex) {
// Note: the ex variable is thrown
// future stack traces of the exception will not see prior calls
throw ex;
}
一般的に使用してthrow ex
スタックトレースを検査し、将来の例外ハンドラのみにまでさかのぼるとして呼び出しを見ることができますよう、望ましくないthrow ex
。 ex
変数を省略し、 throw
キーワードだけを使用すると、元の例外は"バブルアップ"します。
情報を保持しながら別のメソッドから例外をスローする
例外をキャッチして、元の例外スタックを保持しながら、別のスレッドまたはメソッドから例外をスローすることが必要な場合があります。 ExceptionDispatchInfo
これを行うことができExceptionDispatchInfo
:
using System.Runtime.ExceptionServices;
void Main()
{
ExceptionDispatchInfo capturedException = null;
try
{
throw new Exception();
}
catch (Exception ex)
{
capturedException = ExceptionDispatchInfo.Capture(ex);
}
Foo(capturedException);
}
void Foo(ExceptionDispatchInfo exceptionDispatchInfo)
{
// Do stuff
if (capturedException != null)
{
// Exception stack trace will show it was thrown from Main() and not from Foo()
exceptionDispatchInfo.Throw();
}
}