カテゴリー
.NET

例外処理について実験

.NET Framework2.0の例外処理でいろいろと実験してみる。

というのも、VB6のOn Error Gotoの動きはばっちり理解しているけど、Javaから来ているTry?Catchの例外処理の動きがいまいち把握出来ていない。
これが把握できてないと、.NETでどういう例外処理を施せばいいのかがわからない。
VB6の場合は、戻り値をStringにして、エラーメッセージを積み重ねていって、疑似スタックトレースなんてものを作ったりした。
On Error Gotoの仕組みは、うっかりしたことでエラー情報が消失したりして、安全には使えなかったのだな。
つまり戻り値でのエラーチェック。利点としては、必ずエラーが起きた場合を想定して作るので、漏れが少ない。難点はとにかく面倒だということ。
(このあたりはここここに奮闘の記録が残っています)

.NETの場合はフレームワーク自体がバンバン例外を発生させるので、自分の作ったメソッドだけ戻り値でエラーチェックしても、エラー処理が2パターンになって煩雑化する。
ここは、フレームワークの例外処理に沿うのが一番。

そこで、動きを確かめるために、気になるパターンをいろいろ試してみた。


その1 メソッドからメソッドを呼び出して、そこで例外が起きたという基本パターン。

    class Program
    {
        static void Main(string[] args)
        {
            Program p = new Program();
            try
            {
                p.FirstMethod();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);               
                Console.WriteLine(ex.StackTrace);
            }

            Console.WriteLine("Enterキーを押すと終了");
            Console.ReadLine();
           
        }

        private void FirstMethod()
        {
            SecondMethod();
        }

        private void SecondMethod()
        {
            throw new Exception("SecondMethodでエラー");
        }

    }

「SecondMethodでエラー」が表示される。
スタックトレースはSecond、そしてFirstの順で表示。
つまり深いところで起きたエラーの内容がそのまま拾えるということだ。

その2 次にFirstMethodを次のようにしてみた。

        private void FirstMethod()
        {
            try
            {
                SecondMethod();
            }
            catch (Exception ex)
            {
                //なにかのエラー処理

                //そのままエラーを投げてみる
                throw ex;
            }
        }

同じく「SecondMethodでエラー」が表示。
しかし、スタックトレースはFirstのみ表示。Secondは出てこない。なぜだろう?
どこでエラーが起きたかわからなくなりそうだな。
Javaもこんな動きだったっけ?

その3 次にFirstMethodをこんな風にしてみる
        private void FirstMethod()
        {
            try
            {
                SecondMethod();
            }
            catch (Exception ex)
            {
                //新たに例外を起こしてみる
                throw new Exception("だめだぜ子猫ちゃん");
            }
        }

「だめだぜ子猫ちゃん」表示。
スタックトレースもFirstのみ。Secondで起きたエラーの詳細メッセージは消失。
まぁ、それはそうだろう。

その5 InnerExceptionを使ってみる。
        private void FirstMethod()
        {
            try
            {
                SecondMethod();
            }
            catch (Exception ex)
            {
                //InnerExceptionを使ってみる
                throw new Exception("だめだぜ子猫ちゃん",ex);
            }
        }

Mainメソッドも以下のように変更。
        static void Main(string[] args)
        {
            Program p = new Program();
            try
            {
                p.FirstMethod();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
                Console.WriteLine("");
                Console.WriteLine(ex.InnerException.Message);
                Console.WriteLine(ex.InnerException.StackTrace);

            }

            Console.WriteLine("Enterキーを押すと終了");
            Console.ReadLine();

        }

「だめだぜ子猫ちゃん」と、トレースにFirstMethod。
「SecondMethodでエラー」と、トレースにSecondMethod,FirstMethod。

SecondMethodで起きた詳細のエラー情報も消失することなく、FirstMethodでもエラーの情報を付加して呼び出し元に通知できる。

こうやってみると、その1かその5が一番使うパターンかもしれない。
なんらかのエラー処理を行って例外をそのまま呼び出し元に渡すという、その2は結構使うかと思ったけど、スタックトレースが一部消失するのはよろしくない。

そこで、
その6 FirstMethodで例外をキャッチして表示してみる
        private void FirstMethod()
        {
            try
            {
                SecondMethod();
            }
            catch (Exception ex)
            {
                //なにかのエラー処理
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
                //そのままエラーを投げてみる
                throw ex;
            }
            finally
            {
                Console.WriteLine("FirstMethodの終了処理");
            }
        }
「なにかのエラー処理」の後のex.StackTraceではSecondMethodも表示されている。
これ以下スタックトレースはここでログにはき出すので必要ない、とか言う場合はこれでもいいのかもしれない。

この記事を書いた人: A-tak

A-tak.com(えいたっく どっとこむ)の管理人。
Apple野郎なおっさんでしたが、ちょっと最近のAppleには飽き気味。
A-tak.comは2002年2月から運営(前身のサイトは1999年3月から)。今年で18年目!

Twitter
Mastodon
Facebook