【C#】例外処理についてわかりやすく詳しく解説

プログラミング初心者にとって、例外処理は難しい概念の一つです。

C#では、例外処理を行うための仕組みが用意されています。

本記事では、C#での例外処理についてわかりやすく詳しく解説します。

目次

例外処理とは

例外処理とは、プログラムが実行中にエラーが発生した場合に、そのエラーをキャッチして適切な処理を行うことです。

例えば、ファイルが見つからない場合や、データベースへの接続に失敗した場合などが挙げられます。

C#では、try-catch文を使って例外処理を行います。

tryブロック内でエラーが発生する可能性のあるコードを記述し、catchブロックでそのエラーをキャッチして適切な処理を行います。

以下に例を示します。

try
{
    // ここでエラーが発生する可能性のあるコード
}
catch (Exception ex)
{
    // エラーが発生した場合の処理
}

このように、tryブロック内でエラーが発生すると、catchブロックに移動して指定された例外オブジェクト(上記の例ではex)が生成されます。

このオブジェクトには、エラーメッセージやスタックトレースなどの情報が含まれており、これらの情報を利用して適切な処理を行います。

次の見出しでは、具体的な例外処理の行い方について説明します。

C#での例外処理の基本

プログラムを作成する際には、エラーが発生することがあります。

そのような場合には、例外処理を行うことでプログラムの安定性を保つことができます。

C#では、try-catch文やfinallyブロック、throw文などを使って例外処理を行います。

try-catch文の使い方

try-catch文は、エラーが発生する可能性がある箇所をtryブロックで囲み、catchブロックでエラー処理を行います。

以下は、try-catch文の基本的な構文です。

try
{
    // エラーが発生する可能性があるコード
}
catch (Exception ex)
{
    // エラー処理
}

上記の例では、tryブロック内でエラーが発生した場合にはcatchブロックに移ります。

Exceptionクラスはすべての例外クラスの基底クラスであり、どんな種類の例外でもキャッチすることができます。

finallyブロックの使い方

finallyブロックは、必ず実行されるコードを記述します。

以下はfinallyブロックの基本的な構文です。

try
{
    // エラーが発生する可能性があるコード
}
catch (Exception ex)
{
    // エラーが発生したときに行う処理
}
finally
{
    // 必ず実行されるコード
}

上記の例では、エラーが発生してもしなくても必ずfinallyブロック内のコードが実行されます。

throw文の使い方

throw文は、自分で例外を投げるために使用します。

以下はthrow文の基本的な構文です。

if (条件式)
{
    throw new Exception("エラーメッセージ");
}

上記の例では、条件式がtrueだった場合に新しいExceptionオブジェクトを生成し、「エラーメッセージ」を引数に渡して投げられます。

例外を投げた場合、該当の処理がtry-catchで囲まれていないとプログラムが停止します。

以上がC#での例外処理に関する基本的な内容です。

適切なタイミングでこれらを活用し、プログラム全体を安定させましょう。

例外処理の種類

プログラムを実行していると、予期しないエラーが発生することがあります。

このようなエラーを「例外」と呼びます。

C#では、例外処理を行うことで、プログラムの安定性を高めることができます。

C#における例外は、大きく分けて2つの種類に分類されます。

システム例外

システム例外は、.NET FrameworkやWindows OSなどのシステムから発生する例外です。

これらの例外は、アプリケーション開発者が直接制御することはできないため、適切にtry-catchを記述してエラーを処理する必要があります。

代表的なシステム例外には、NullReferenceExceptionDivideByZeroExceptionなどがあります。

アプリケーション例外

アプリケーション例外は、アプリケーション自身が発生させる例外です。

これらの例外は、アプリケーション開発者が直接制御することができるため、不正な入力を検出したら例外を投げてエラー処理を行うといったことが可能です。

代表的なアプリケーション例外には、ArgumentExceptionInvalidOperationExceptionなどがあります。

例外のハンドリング

C#では、try-catch-finally文を使って、例外処理を行います。

tryブロック内でエラーが発生した場合、catchブロックにジャンプし、エラー処理を行います。

finallyブロックは必ず実行されるため、ファイルやデータベース接続などのクリーンアップ処理に利用されます。

以下は、try-catch-finally文の基本的な構文です。

try
{
    // 通常時に実行するコード
}
catch (Exception ex)
{
    // 例外時に実行するコード
}
finally
{
    // 必ず実行されるコード
}

また、throw文を使って、自分で意図的にエラーを発生させることもできます。

throw文を使うことで、特定の条件下で強制的にエラー処理を実施することも可能です。

以上がC#における基本的な例外処理方法です。

例外処理のベストプラクティス

例外処理は、プログラムの安定性を高めるために非常に重要な機能です。

しかし、適切な方法で実装されていない場合、逆に問題を引き起こす可能性があります。

このセクションでは、例外処理のベストプラクティスについて説明します。

例外のログ出力

例外が発生した場合、その原因を特定するためにログ出力が必要です。

ログ出力は、デバッグやトラブルシューティング時に非常に役立ちます。

また、アプリケーションの稼働中に発生したエラーを把握するためにも必要です。

C#では、System.Diagnostics名前空間内のTraceクラスやDebugクラスを使用して簡単にログ出力を行うことができます。

try
{
    // 何らかの処理
}
catch (Exception ex)
{
    Trace.WriteLine("エラーが発生しました:" + ex.Message);
}

例外の再スロー

例外が発生した場合、そのまま上位レイヤーへ伝えるだけでは不十分な場合があります。

上位レイヤーで適切な処理を行うためには、例外情報を詳細かつ正確に伝える必要があります。

再スローとは、キャッチされた例外をそのまま上位レイヤーへ投げることです。

これにより、上位レイヤーで適切な処理を行うことができます。

using System;


class Program
{
    static void Sample(){
        try
        {
            // 何らかの処理
        }
        catch (Exception ex)
        {
            throw; //呼び出し元に例外処理を引き継ぐ
        }

    }
    
   static void Main(string[] args)
   {
        try
        {
           //ここのtry-catchスコープがSampleメソッドにとっての上位レイヤー
            Sample();
        }
        catch (Exception ex)
        {
            //Sampleで起きた例外を受け取る
            //例外処理
        }
   }
}

例外処理の委譲

複数のメソッドから呼び出される場合や複数人で開発する場合は、各メソッド内で同じような例外処理コードを書く必要があります。

これは冗長的でメンテナンス性も低くなります。

そこで、共通部分だけ別メソッドとして切り出し、各メソッドから呼び出す方法があります。

これによりコード量も減り可読性も向上します。

public void DoSomething()
{
    try
    {
        // 何らかの処理
    }
    catch (Exception ex)
    {
        //汎用的な例外処理を行うメソッド
        HandleException(ex);
    }
}

private void HandleException(Exception ex)
{
    // 共通的なエラーハンドリング処理
}

例外のハンドリングの例外

一般的なエラーハンドリングコードでも予期しないエラーが発生する可能性があります。

このような場合でもアプリケーション全体が停止しないよう対策する必要があります。

一般的な方法はtry-catch文内でさらにtry-catch文を入れて対応します。

try 
{
   // 何らかの処理 
} 
catch (Exception ex) 
{ 
   try 
   { 
      // エラーハンドリングコード 
   } 
   catch(Exception innerEx) 
   {  
      Trace.WriteLine("二重エラー:" + innerEx.Message);  
   }  
}

このようにすることで、「ファイルオープン失敗による例外」→「別のファイルオープン失敗による例外」のような連続した例外もキャッチしてアプリケーションが停止しないように対策することができます。

例外の処理のテスト

最後に、正しく動作することを確認するためにテストコードも含めることが重要です。

特定条件下で意図した結果(成功または失敗)を返すことを確認するテストコードは品質保証面でも非常に重要です。

[Test]
public void TestMethod()
{
    try
    {
        // テスト対象メソッド呼び出し
        //必要に応じて意図的に例外を発生させることも大事
        Assert.Fail("Expected exception not thrown");
    }
    catch (Exception ex)
    {
        Assert.AreEqual(typeof(ArgumentException), ex.GetType());
        Assert.AreEqual("Invalid argument", ex.Message);
     }
}

以上がC#での例外処理のベストプラクティスです。

これらを実践することで安定したアプリケーション開発・保守・改善・品質保証等々効率的かつ効果的な開発活動・業務運用等々支援される事間違い無しです!

目次