C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[5]: エラーメッセージの表示方法について


(過去ログ 79 を表示中)

[トピック内 14 記事 (1 - 14 表示)]  << 0 >>

■46708 / inTopicNo.1)  エラーメッセージの表示方法について
  
□投稿者/ へらぶな (1回)-(2010/02/09(Tue) 16:21:25)

分類:[.NET 全般] 

皆さんこんにちは。へらぶなと申します。
今回は皆さんのお知恵をお借りしたく投稿させて頂きました。
初歩的な内容で申し訳ありません。

使用環境:WindowsXP,Microsoft Visual Basic 2008 Express

    下記のソースを実行すると、「HOGEB」でエラーが発生しているのに、
    「HOGEAでエラーが発生しました」と表示されます。

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
    Handles Button1.Click

        Try
            HOGE()
        Catch ex As Exception
            Messagebox.Show(ex.Message)
        End Try

    End Sub

    Private Sub HOGE()

        Try
            HOGEA()

            Try
                HOGEB()

            Catch ex As Exception
                Throw New Exception("HOGEBでエラーが発生しました")
            End Try

        Catch ex As Exception
            Throw New Exception("HOGEAでエラーが発生しました")
        End Try

    End Sub

    Private Sub HOGEA()
        'なんか処理
    End Sub

    Private Sub HOGEB()
        '例外をスロー
        Throw New Exception
    End Sub

  やりたいことは、
  @エラーのメッセージボックスは呼び出し元で一括管理したい。
   (HOGE,HOGEA,HOGEBにメッセージボックスをつけたくない)
  
  A発生した例外をそのままスローしても、エラーメッセージがわかりにくいため、
   独自のエラーメッセージをスローしたい。

  問題は、
   やりたいことAを実行しようとすると、各Catch部でエラーメッセージが上書きされるため、
   上記のように本来「HOGEB」で例外が発生しているにも拘らず、「HOGEA」でエラーが
   発生したようにメッセージが表示されてしまう。
  
  おそらく非常に初歩的な質問かと思いますが、当方には解決方法がわからず。。。
  皆さんが普段どのようにエラーメッセージを表示させているかもご教授頂けるとありがたいです。

  どうかよろしくお願いいたします。

引用返信 編集キー/
■46710 / inTopicNo.2)  Re[1]: エラーメッセージの表示方法について
□投稿者/ Mr.T (330回)-(2010/02/09(Tue) 17:26:04)
わざわざNewしてるからそこがエラー箇所になってしまいますよね。

エラー内容を保持するようなプロパティなりをつくって、そこにメッセージ
を格納するようにしたらいいんじゃないですかね?


引用返信 編集キー/
■46717 / inTopicNo.3)  Re[1]: エラーメッセージの表示方法について
□投稿者/ Jitta on the way (549回)-(2010/02/09(Tue) 18:52:56)
No46708 (へらぶな さん) に返信

まず、エラーをキャッチしなければならないものか、検討してください。キーパー以外がキャッチすると、ハンドの反則です。キーパーも、ペナルティーエリア外では反則です。味方のパスも、キャッチしたら反則です。

開発中に、例外が出ないように修正してください。例外は、「例外的な状況」でのみ、出ます。

アプリケーションで例外を送出する場合は、独自のクラスを作り、そこから適切なクラスへと継承してください。


こうすると、最上位の例外クラスである Exception をキャッチするコードはなくなるはずです。
引用返信 編集キー/
■46756 / inTopicNo.4)  Re[2]: エラーメッセージの表示方法について
□投稿者/ へらぶな (3回)-(2010/02/10(Wed) 12:11:06)
Mr.T様 Jitta on the way 様 返信ありがとうございます。

Mr.T様
>エラー内容を保持するようなプロパティなりをつくって、そこにメッセージ
>を格納するようにしたらいいんじゃないですかね?

私が最初に思いついたのがこれでした。やはりこれしかないのかと思っておりました。

Jitta on the way 様
>開発中に、例外が出ないように修正してください。例外は、「例外的な状況」でのみ、出ます。
了解です。

以下、理解力不足で申し訳ありません。
>アプリケーションで例外を送出する場合は、独自のクラスを作り、そこから適切なクラスへと継承してください。
例えばHOGEAException例外クラスを作る等、ということでしょうか?

そうすると、例えば、
    Private Sub HOGE()

        Try
            HOGEA()

            Try
                HOGEB()

            Catch ex As HOGEBException
                Throw ex 
            End Try

        Catch ex As HOGEBException
            Throw ex

        Catch ex As HOGEAException
            Throw ex

        End Try

    End Sub

のようになりますでしょうか?

引用返信 編集キー/
■46757 / inTopicNo.5)  Re[3]: エラーメッセージの表示方法について
□投稿者/ nori (82回)-(2010/02/10(Wed) 12:20:11)
>問題は、
>   やりたいことAを実行しようとすると、各Catch部でエラーメッセージが上書きされるため、
>   上記のように本来「HOGEB」で例外が発生しているにも拘らず、「HOGEA」でエラーが
>   発生したようにメッセージが表示されてしまう。

    Private Sub HOGE()
        Try
            HOGEA()
        Catch ex As Exception
            Throw New Exception("HOGEAでエラーが発生しました")
        End Try

        Try
            HOGEB()
        Catch ex As Exception
            Throw New Exception("HOGEBでエラーが発生しました")
        End Try
    End Sub

じゃ駄目なの?

引用返信 編集キー/
■46762 / inTopicNo.6)  Re[1]: エラーメッセージの表示方法について
□投稿者/ kyo (9回)-(2010/02/10(Wed) 13:17:40)
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles Button1.Click

Try
HOGE()
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try

End Sub

Private Sub HOGE()

HOGEA()
HOGEB()

End Sub

Private Sub HOGEA()
'なんか処理
End Sub

Private Sub HOGEB()
'例外をスロー
Throw New Exception("HOGEB")
End Sub

じゃ駄目なの?
引用返信 編集キー/
■46772 / inTopicNo.7)  Re[2]: エラーメッセージの表示方法について
□投稿者/ へらぶな (4回)-(2010/02/10(Wed) 14:33:44)
nori様 kyo様 返信ありがとうございます。
確かにお二人の方法でうまく行きそうなのですが、例えば下記のようにHOGECがFinally文とともに
追加になると、話は変わってきますでしょうか?(すいません。ちょっと今混乱しています。。。)
※コメントは例えばの処理です。

  Private Sub HOGE()

        Try
      'DBのオープン処理
            HOGEA()

            Try
        'SQL文の実行
                HOGEB()

            Catch ex As HOGEBException
                Throw ex 
            End Try

        Catch ex As HOGEBException
            Throw ex

        Catch ex As HOGEAException
            Throw ex
    Finally
            'DBのクローズ処理
      HOGEC()
        End Try

    End Sub

引用返信 編集キー/
■46778 / inTopicNo.8)  Re[3]: エラーメッセージの表示方法について
□投稿者/ GOD (28回)-(2010/02/10(Wed) 17:17:41)
これでどうですか?
Try
    HOGEA()
    Try
        HOGEB()
    Catch ex As Exception
        Throw New Exception("HOGEB", ex)
    End Try
Catch ex As Exception
    If ex.InnerException Is Nothing Then
        Throw New Exception("HOGEA", ex)
    Else
        Throw ex
    End If
End Try

引用返信 編集キー/
■46780 / inTopicNo.9)  Re[1]: エラーメッセージの表示方法について
□投稿者/ 魔界の仮面弁士 (1485回)-(2010/02/10(Wed) 17:33:45)
No46708 (へらぶな さん) に返信
> Catch ex As Exception
>     Throw New Exception("HOGEBでエラーが発生しました")
> End Try

基本的に、素の Exception を Catch すべきではありません。

本来処理すべきではない例外……たとえば、引数の設定ミスによる
ArgumentOutOfRangeException など……を握りつぶしてしまうと、
バグの発見を遅らせる要因となります。

例外処理では、必要最低限の例外のみを Catch するようにしてください。
もし、処理すべきではない例外を Catch した際には、下手に加工せずに
その例外をそのまま再 Throw するようにした方がよいかと。


また、素の Exception クラスを New することも好ましくありません。
これについては後述します。



■No46756 (へらぶな さん) に返信
>> アプリケーションで例外を送出する場合は、独自のクラスを作り、そこから適切なクラスへと継承してください。
> 例えばHOGEAException例外クラスを作る等、ということでしょうか?

System.Exception から直接生成してしまうと、例外を管理しにくくなるため、
「Throw New Exception("HOGEAでエラーが発生しました")」のように
素の Exception クラスを生成することは、あまりおすすめしません。

カスタム例外を管理する場合には、「基本となる例外クラス」を用意しておき、
さらにそれを継承させた例外クラスを利用したほうが、管理しやすいかと思います。
http://msdn.microsoft.com/ja-jp/library/ms954599.aspx#exceptdotnet_topic5


たとえば、ファイル入出力関係の例外クラスとして、
 System.IO.IOException
が定義されていますが、これらはさらに、
 DirectoryNotFoundException
 EndOfStreamException
 FileNotFoundException
 FileLoadException
 PathTooLongException
などの、より詳細な例外クラスへと継承されています。

このような継承関係にしておくと、たとえば個々の例外を
 Catch ex As PathTooLongException
 Catch ex As FileNotFoundException
 Catch ex As DirectoryNotFoundException
などで処理するだけではなく、関連するこれらの例外を
 Catch ex As IOException
でまとめて処理させることもできるようになります。


このあたりの例外設計が適切ではなかった場合、
 Catch ex As Exception
のように、無差別に例外を Catch せざるを得なくなってしまうため、
利用側が例外処理を実装しにくくなってしまいます。



■No46772 (へらぶな さん) に返信
> Catch ex As HOGEBException
>     Throw ex 
> End Try

上記は、何のために Catch しているのでしょうか?
何もせずに例外を投げ直すだけならば、そもそも Try/Catch する必要は無いと思います。

また、「Throw」と「Throw ex」の違いは認識されていますでしょうか。
例外には発生箇所を示す情報が埋め込まれていますが、Throw ex してしまうと、
そこが新たな発生地点となり、もともとが HogeB で発生したという情報が
握りつぶされてしまいます。

意図的に『握りつぶしている』のであればそれでも良いですが、
例外を単に『素通りさせたい』のであれば、引数無しでそのまま「Throw」させましょう。

また、ほとんどの例外クラスは、innerException As Exception を受け取るための
コンストラクタを用意しています。もしも別の例外に『置き換えたい』のであれば、
 Throw New HOGEBException("別のメッセージ", ex)
のように実装してみましょう。こうすれば 呼び出し元では、
ex.InnerException を辿って、元の例外を解析できるようになります。

引用返信 編集キー/
■46790 / inTopicNo.10)  Re[3]: エラーメッセージの表示方法について
□投稿者/ 魔界の仮面弁士 (1486回)-(2010/02/10(Wed) 18:24:24)
No46772 (へらぶな さん) に返信
> 例えば下記のようにHOGECがFinally文とともに
> 追加になると、話は変わってきますでしょうか?

やりたいことは、
>> (1)エラーのメッセージボックスは呼び出し元で一括管理したい。
>>  (HOGE,HOGEA,HOGEBにメッセージボックスをつけたくない)
>> (2)発生した例外をそのままスローしても、エラーメッセージがわかりにくいため、
>>  独自のエラーメッセージをスローしたい。
でしたよね。

上記を実現するに当たり、今回のコードでは、内側の Catch と外側の Catch とで、
それぞれ何の処理を担当させようとしているのでしょうか?


今回( No46772 )のコードでは、個々の Catch 文で再スローしか行われていないため、

  Try
    HOGEA()    'DBのオープン処理
    HOGEB()    'SQL文の実行
  Finally
    HOGEC()    'DBのクローズ処理
  End Try

と大差無いように見えました。(「Throw」と「Throw ex」の差はありますが)


また、外側の Catch 句で、個々の例外を Catch していますが、この場合

  Catch ex As HOGEAException
    MsgBox("データベースに接続できませんでした。管理者に連絡してください。", vbCritical)
  Catch ex As HOGEBException
    Trace.WriteLine(ex.GetType().FullName)
    Trace.WriteLine(ex.Message)
    Trace.WriteLine(ex.SQL)
    Trace.WriteLine(ex.StackTrace)
    Throw

などの個別記述が必要になってしまう気がしますが、それは
> (1)エラーのメッセージボックスは呼び出し元で一括管理したい。
>  (HOGE,HOGEA,HOGEBにメッセージボックスをつけたくない)
の要件を満たせているのでしょうか?


で、もしも
> (2)発生した例外をそのままスローしても、エラーメッセージがわかりにくいため、
>  独自のエラーメッセージをスローしたい。
のメッセージ変換を、外側の Catch だけで行えるのであれば、内側の Catch 句は
不要だと思います。もし二重に使うにしても、それは別の目的に使う場合だけかと。

  Try
    Try
      HOGEA()    'DBのオープン処理
    Catch ex As HOGEAException
      Trace.WriteLine(ex.ServerName & "に接続失敗、セカンダリに接続")
      HogeA2()   'リカバリー処理(代理DBのオープン)
    End Try
    Try
      HOGEB()    'SQL文の実行
    Catch ex As HOGEBException
      SQLLog(ex)  '失敗した SQL をログに記録しておく
      Throw       'リカバリー不能なので上位に再スロー
    End Try
  'Catch ex As HOGEException   'HOGEAException/HOGEBExceptionの継承元クラス
  '   ShowMessage(ex)    'Exception の内容に応じて「わかりやすいメッセージ」を表示するメソッド
  Finally
    HOGEC()    'DBのクローズ処理
  End Try


あるいはその逆に、
> (2)発生した例外をそのままスローしても、エラーメッセージがわかりにくいため、
>  独自のエラーメッセージをスローしたい。
のメッセージ変換を、(外側ではなく)内側の Catch 句にて行わせたいのであれば、
GOD さんが No46778 で書かれたように、InnerException を使って Throw し、
それを外側で処理するというのもひとつの手かと思います。

引用返信 編集キー/
■46795 / inTopicNo.11)  Re[2]: エラーメッセージの表示方法について
□投稿者/ Jitta on the way (552回)-(2010/02/10(Wed) 19:26:00)
No46780 (魔界の仮面弁士 さん) に返信

すっかり、しかもスッキリと書かれてしまいましたw

StackTrace を追加しておきます。
(「開発中に、例外が出る要素を潰せ」ってことで)



へらぶなさん:
例外のクラスは、漫然と作られている訳ではありません。そのクラスを見ただけで、不都合の理由を絞り込めるように設計されています(設計してください)。
例外のメッセージは、エンド ユーザーには見せないように、設計してください。メッセージが“エンド ユーザーにとって”わかりにくいのは、開発者のために設計されているからです。だから、開発中に、例外が発生する要因を潰してください。
引用返信 編集キー/
■46797 / inTopicNo.12)  Re[3]: エラーメッセージの表示方法について
□投稿者/ なちゃ (389回)-(2010/02/10(Wed) 20:43:25)
クライアントに見せたいメッセージが別途考えられる場合は、
ExceptionのDataプロパティに何らかのキーで格納しておくことも出来ます。

これだと、メッセージを追加するためだけに例外をラップしたりする必要がありませんので、
個人的にはおすすめの方法です。

メッセージ以外にも、エラー処理に関するいろんな追加情報を保存するのに使えます。

引用返信 編集キー/
■46848 / inTopicNo.13)  Re[4]: エラーメッセージの表示方法について
□投稿者/ へらぶな (5回)-(2010/02/12(Fri) 10:46:46)
GOD様 魔界の仮面弁士様 Jitta on the way様 なちゃ様
ご返信ありがとうございます。

まだまだ勉強不足で皆様の返信をすべて理解できたわけではないのですが、
まずはお礼をと思い返信させていただきました。

皆様の返信を読ませていただいて、自分がいかに勉強不足かということを痛感致しました。

皆様のアドバイスを元にもう一度自分が書いたコードを読み直してみて、
改善して行こうと思います。

引用返信 編集キー/
■46852 / inTopicNo.14)  Re[5]: エラーメッセージの表示方法について
□投稿者/ nori (83回)-(2010/02/12(Fri) 11:26:07)
> nori様 kyo様 返信ありがとうございます。
> 確かにお二人の方法でうまく行きそうなのですが、例えば下記のようにHOGECがFinally文とともに
> 追加になると、話は変わってきますでしょうか?(すいません。ちょっと今混乱しています。。。)
> ※コメントは例えばの処理です。
> 
>   Private Sub HOGE()
>         Try
>       'DBのオープン処理
>             HOGEA()
>             Try
>         'SQL文の実行
>                 HOGEB()
>             Catch ex As HOGEBException
>                 Throw ex 
>             End Try
>         Catch ex As HOGEBException
>             Throw ex
>         Catch ex As HOGEAException
>             Throw ex
>     Finally
>             'DBのクローズ処理
>       HOGEC()
>         End Try
>     End Sub

    Private Sub HOGE()
        Try
           Try
               HOGEA()
           Catch ex As Exception
               Throw New Exception("HOGEAでエラーが発生しました")
           End Try

           Try
               HOGEB()
           Catch ex As Exception
               Throw New Exception("HOGEBでエラーが発生しました")
           End Try
        Finally
       HOGEC()
        End Try
    End Sub

例外を握りつぶすのが駄目なのは分ったと思いますが、とりあえず参考にどうぞ。

引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -