読者です 読者をやめる 読者になる 読者になる

C#例外処理でのthrowとthrow exの違い

C#の例外処理におけるThrowの扱い方の違いのメモ。
C#/VB.NETでは、「throw;」を使うほうが推奨されることが多いです。「throw ex;」を使うとそれまでの情報(スタックトレースやInnerException)がクリアされます。
以下は、その確認コードです。

//ゼロ除算エラーを発生させる関数
private void ZeroDivide()
{
    int zero = 0;
    int err = 1 / zero;
}

//exを付けてThrowする関数
private void ThrowEx()
{
    try
    {
        ZeroDivide();
    }
    catch (Exception ex)
    {
        //exを付けて投げる
        throw ex;
    }
}

//ex無しでThrowする関数
private void ThrowOnly()
{
    try
    {
        ZeroDivide();
    }
    catch (Exception ex)
    {
        //exを付けないで投げる
        throw;
    }
}

//ThrowExをテスト
private void button1_Click(object sender, EventArgs e)
{
    try
    {
        ThrowEx();
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.ToString());
    //
    //→「throw ex;」時のメッセージ
    //
    //System.DivideByZeroException: 0 で除算しようとしました。
    //   場所 Form1.ThrowEx() 場所 C:\Sample\Form1.cs:行 38
    //   場所 Form1.button1_Click(Object sender, EventArgs e) 場所 C:\Sample\Form1.cs:行 60
    //
    //※本当はZeroDivide関数でエラーが発生したがThrow前の情報が消えている。
    // ThrowEx関数でエラーが発生したかのように見える。
    }
}

//ThrowOnlyをテスト
private void button2_Click(object sender, EventArgs e)
{
    try
    {
        ThrowOnly();
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.ToString());
    //
    //→「throw;」時のメッセージ
    //
    //System.DivideByZeroException: 0 で除算しようとしました。
    //   場所 Form1.ZeroDivide() 場所 C:\Sample\Form1.cs:行 26
    //   場所 Form1.ThrowOnly() 場所 C:\Sample\Form1.cs:行 50
    //   場所 Form1.button2_Click(Object sender, EventArgs e) 場所 C:\Sample\Form1.cs:行 72
    //
    //※エラー発生元であるZeroDivideのスタックトレースが消えずに残っている。
    }
}