例外処理というのは、なんらかの異常や条件を満たしていなかったときに行う処理のこ
とです。
例外を投げると、続く処理をやめ、すぐに例外処理に飛びます。
Cでは、例えば複数のネストのなかにあるループの処理中に異常が発生した場合、どう
やって抜けるか、gotoを使うべきか、などといった話題が出たものですが、C#ではtry/
chatchという異常時に行う命令が追加されています。
例えば、Cでは以下のような場合gotoを使わないとかなり面倒な処理をしなければなりま
せん。
while( 1 )
{
while( 1 )
{
//ここで問題が発生 ループから抜けたい
}
}
C#なら、例外を投げるだけですみます。
上記のような特殊ケースはもとより、異常発生時は続く処理を行わないというのは殆ど
の場合当てはまるケースです。
なので、アプリケーションを作成していると、例外処理を書かないというのはあまり無
いといっていいでしょう。
私はコピープログラムで以下のようなコードを書きました。
private void CopyFile(string src, string dest)
{
StreamReader sr = new StreamReader(src , Encoding.GetEncoding("shift_jis"));
StreamWriter sw = new StreamWriter(dest, false, Encoding.Unicode);
while (!sr.EndOfStream )
{
string ReadText;
ReadText = sr.ReadLine();
sw.WriteLine(ReadText);
sw.Flush();
}
sr.Close();
sw.Close();
}
private void button1_Click(object sender, EventArgs e)
{
if (!textBox1.Text.Equals("")
&& !textBox2.Text.Equals(""))
{
if (File.Exists(textBox1.Text))
{
CopyFile(textBox1.Text, textBox2.Text);
}
else
{
MessageBox.Show("コピー元のファイルは存在しないか、パスが不正です");
}
}
else
{
MessageBox.Show("コピー元/コピー先のファイル名を入力してください");
}
}
ボタンクリックイベントの処理は、間違いではないですが、ちょいと見づらいコードです。
例外処理を使うと、こんな感じになります。
private void button1_Click(object sender, EventArgs e)
{
try
{
if ( textBox1.Text.Equals("")
|| textBox2.Text.Equals(""))
{
throw new Exeption("コピー元/コピー先のファイル名を入力してください");
}
if( (File.Exists(textBox1.Text) )
{
throw new Exeption("コピー元のファイルは存在しないか、パスが不正です");
}
CopyFile(textBox1.Text, textBox2.Text);
}
catch( Exeption ex )
{
MessageBox.Show( ex.Message );
}
}
幾分すっきりしました。
でも、実は、C#の殆どのメソッドは、引数などのチェックを行ってくれます。
そのとき、異常があった場合は例外処理を投げてくれるのです。
つまり、自分でこのようなチェックを行う必要は無かったりします。
そこいらを考慮してプログラムを作成すると……
private void button1_Click(object sender, EventArgs e)
{
try
{
CopyFile(textBox1.Text, textBox2.Text );
}
catch (ArgumentException ex)
{
MessageBox.Show( ex.Message);
}
}
で、済みます。
簡単ですね。
エラーメッセージもコンパイラ側が用意してくれたものが表示されるので、意味不明な
エラーにはならないというメリットもあります(知っている人が見ればすぐ分かる)
まず、例外が発生する可能性のある場所、つまり、例外処理を行いたい部分をtryで囲み
ます。
そして、tryの下に例外が発生した場合に行う処理を、catchで囲みます。
例外が発生したしないに関わらず行いたい処理があればcatchの下にfinallyで囲みます。
try
{
//ここに例外が発生する可能性の有り処理を記述
}
catch( Exception ex )
{
//例外が発生した場合の処理を記述
}
finally
{
//例外の発生有無にかかわらず行いたい処理をここに記述
//無くてもかまわない
}
C#のメソッドで問題が発生した場合、例外を投げてくれるのは先ほど説明しましたが、
例外をプログラマが投げたい場合は、throwキーワードを使用します。
C++とちがって、文字列や数値型を投げることは出来ません。
例外用クラスが用意されているので、それを使います。
例外用クラスは、基本クラスのExeptionや、引数が異常のときに投げるArgumentExeption
等、目的によって使うクラスを使い分けることが出来ます。
例外を投げる際は、インスタンス化してある例外クラスを投げるか、throwキーワードの
後にnewキーワードを用います。
コンストラクタは幾つかオーバーロードされています。
これについてはの地ほど説明を行います。
投げた例外は、catchキーワードのカッコ内で、対象の例外クラスと、オブジェクト名を
記述して受け取ります。
C++と違って、どのような例外でも受け取る「...」は使えません。
また、catchは複数記述することが出来ます。
例えば、引数例外であるArgumentExeptionと、システム例外であるSystemExeptionで、
異なる処理を記述できます。
メソッド内にcatchキーワードが無い場合、メソッドの呼び出し元に例外の発生を知らせ
ます。
ファイルコピーの例を見てください。
例外が発生するのはCopyFileメソッドですが、例外を受け取って処理を行っているのは
button1_Clickイベントです。
例
private void Method()
{
throw new Exception(); //例外を投げる
}
private void button1_Click(object sender, EventArgs e)
{
try
{
Method(); //呼び出し元
}
catch( Exception ex )
{
//Methodで投げた例外を処理
MessageBox.Show("ボタンクリックイベントで例外を処理");
}
}
catchの中で、更に例外を投げることも出来ます。
これは、メソッド内で例外処理を行った後、メソッドの送信元でも例外処理を行いたい
時などに使用します。
その際は、投げる例外を省くと(つまり、throwだけを記述すると)受け取った例外をそ
のまま投げてくれます。
private void Method()
{
try
{
throw new Exeption(); //例外を投げる
}
catch( Exception ex )
{
//例外を処理する
MessageBox.Show("メソッドで例外を処理");
throw; //ここで受け取った例外を更に投げる
}
}
private void button1_Click(object sender, EventArgs e)
{
try
{
Method(); //呼び出し元
}
catch( Exception ex )
{
//Methodのcatchで投げた例外は、ここで処理される
MessageBox.Show("ボタンクリックイベントで例外を処理");
}
}
例外が発生した・しないにかかわらず行いたい処理があればfinallyの括弧内に処理を
記述します。
C++のようにcatchの後にコードを書いてもほぼ同じように動作しますが、finallyは、
catchの中で、例外を投げてもfinallyに記述したコードが実行されるという点が異なり
ます。
例えば、以下の例では「共通の処理?」は表示されません。
private void Method()
{
try
{
throw new Exeption();
}
catch( Exception ex )
{
throw;
}
MessageBox.Show("共通の処理?");
}
private void button1_Click(object sender, EventArgs e)
{
try
{
Method();
}
catch( Exception ex )
{
MessageBox.Show("ボタンクリックイベントで例外を処理");
}
}
Methodを以下のようにすれば、メッセージが表示されます。
private void Method()
{
try
{
throw new Exception();
}
catch( Exception ex )
{
throw;
}
finally
{
MessageBox.Show("共通の処理!");
}
}
例外クラスのコンストラクタは幾つかオーバーロードされていますが、よく使うのはパ
ラメータが空のものと、文字列を渡すものでしょう。
文字列を渡すと、Messageプロパティに渡した文字がセットされます。
例
private void button1_Click(object sender, EventArgs e)
{
try
{
throw new Exception("例外発生");
}
catch( Exception ex )
{
MessageBox.Show( ex.Message );
}
}
例外クラスの派生クラス、例えばArgumentException等はコンストラクタやプロパティが
追加されていたりしますが、基本的な使い方は一緒です。
最終更新:2007年10月29日 12:47