- PR -

例外処理について

1
投稿者投稿内容
未記入
大ベテラン
会議室デビュー日: 2006/05/19
投稿数: 125
投稿日時: 2006-07-11 16:48
例外処理で過去記事を検索し読んできました。
なんだか自分の例外処理が間違っているのでは!?と不安になったので質問させてください。

現在のシステムは発注元様が色々なクラスを作っております。
私はその1端を開発しております。


たとえばデータベースアクセスクラスなるものがあったとします。
SELECT文を一つ投げるのでも
結果がDataSetでほしければGetDataSetメソッド
結果がDataTabeleでほしければGetDataTableメソッド
結果がDataRowでほしければGetDataRowメソッド
結果が1行1フィールドの場合GetDataObjectメソッド
などなどほかにもたくさんあります。

呼び出し元から各メソッドのVyRef引数にDataSet、DataTable、DataRow、Objectなどを渡してやると
そこにデータを入れてくれるんです。

各メソッドの戻り値はBooleanで異常時True、正常時Falseを返します。
たとえばGetDataRowメソッドでDataSet.DataTable(0).Rows(0)をVyRef引数にセットしてくれるんですが
Rows(0) が NothingだったらTrueが返るんです。「True」です。「False」ではありません。

内部で例外が発生すると例外をログに書き込み且つエラーメッセージを表示し例外はThrowしてくれません。
戻り値「True」が返ります。

SELECT文を投げるときはデータベースアクセスクラスの各メソッドを使用しなくてはなりません。お約束です。
データベースアクセスクラスを修正することもナシです。


ここからが本題です。
各メソッドを使うかぎり、自由にコードを書いていいのですが例外処理についても同様に自由です。

データベースアクセスクラスが何をして、戻り値が何で、どんな例外をThrowするのか
ソースを読めばわかりますがメンドクサイので
すべての例外をExceptionでCatchし最上位のコードまで例外を再Throwさせて最上位で処理するようにしています。
これはゴールキーパー以外はハンドで反則になるのでしょうか?

private sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Try

Call SubTest1

Catch ex As ApplicationException
messagebox.show(ex.Message)
Catch ex As Exception
WriteLog(ex.ToString)
messagebox.show(ex.ToStrin)
End Try
End Sub

Private Sub SubTest1
Dim datarow as DataRow
Dim sql as new System.Text.StringBuilder(String.Empty)

Try

'予想しうる例外
If ("").Equals(Me.TextBox1.Text.Trim) Then
Me.TextBox1.Focus()
Throw New ApplicationException("テキストボックス1が未入力です。")
End If


'SELECT文を投げDataRow取得
sql.Append(" SELECT COUNT(*) FROM table1")
sql.Append(" WHERE field1 = '" & Me.TextBox1.Text.Trim & "'")
call データベースアクセスクラス.GetDataTable(datarow,sql.tostring)

’予想しない例外
if datarow is Nothing Then
Throw new Exception("DataRowオブジェクトが取れないよ。")
End If


Catch ex As ApplicationException
throw(ex.message)
Catch ex As Exception
throw(ex.ToString)
End Try
End Sub
たつごろー
ぬし
会議室デビュー日: 2004/10/25
投稿数: 496
投稿日時: 2006-07-11 18:37
なぜか、私の直前の書き込みから本文がぬけてたので、再度。

引用:

データベースアクセスクラスが何をして、戻り値が何で、どんな例外をThrowするのか
ソースを読めばわかりますがメンドクサイので
すべての例外をExceptionでCatchし最上位のコードまで例外を再Throwさせて最上位で処理するようにしています。
これはゴールキーパー以外はハンドで反則になるのでしょうか?



なります。



この辺は、通称「赤間本」に詳しく出ています。

「.NETエンタープライズWebアプリケーション開発技術大全シリーズ」



「発注元様」のクラスにも問題があるように思います。
.NETではどのようなコードで書くべきか、については、MSから出ている多くの
サンプルから掴み取るのがよいと思います。
Enterprise Library for .NET Framework 2.0は、多くのコードが公開されて
いる、膨大なサンプル郡です。
この辺を少し読むだけでも、設計によい変化があらわれると思います。

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/EntLib2.asp

_________________
たつごろー
codeseek
こみゅぷらす
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2006-07-11 18:48
途中の説明が理解できているか微妙なので、本題だけ...

引用:

未記入さんの書き込み (2006-07-11 16:48) より:

ここからが本題です。
各メソッドを使うかぎり、自由にコードを書いていいのですが例外処理についても同様に自由です。

データベースアクセスクラスが何をして、戻り値が何で、どんな例外をThrowするのか
ソースを読めばわかりますがメンドクサイので
すべての例外をExceptionでCatchし最上位のコードまで例外を再Throwさせて最上位で処理するようにしています。
これはゴールキーパー以外はハンドで反則になるのでしょうか?


然るべき処理が必要だからこそ、例外処理が書いてあるという前提で考えれば、
Catch した例外を 「Throw」 とだけ書いて、上位に伝えるのは問題ありません。

「予見」 できないもの全部 Catch しているとなると、'ペナルティ エリア外' になってしまうと思います。

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2006-07-11 22:58
引用:

じゃんぬねっとさんの書き込み (2006-07-11 18:48) より:

「予見」 できないもの全部 Catch しているとなると、'ペナルティ エリア外' になってしまうと思います。


 ゴールキーパーでもキャッチすると反則、、、ですね(^-^;

# 昔、「じゃ、相手のペナルティエリアでは?」と聞いたやつがいた。。。
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2006-07-11 23:14
引用:

未記入さんの書き込み (2006-07-11 16:48) より:

たとえばデータベースアクセスクラスなるものがあったとします。
SELECT文を一つ投げるのでも
結果がDataSetでほしければGetDataSetメソッド
結果がDataTabeleでほしければGetDataTableメソッド
結果がDataRowでほしければGetDataRowメソッド
結果が1行1フィールドの場合GetDataObjectメソッド
などなどほかにもたくさんあります。

呼び出し元から各メソッドのVyRef引数にDataSet、DataTable、DataRow、Objectなどを渡してやると
そこにデータを入れてくれるんです。


 Get の場合、たいてい、戻り値で返ってくるようにしませんか?これだと、Put とか SetInto とか???


引用:

内部で例外が発生すると例外をログに書き込み且つエラーメッセージを表示し例外はThrowしてくれません。
戻り値「True」が返ります。


それは、実装のひとつとしてアリだと思います。ただ、本当に処理を継続しなければならないのか、というところを考え直すと、ナシになるかもしれません。


引用:

SELECT文を投げるときはデータベースアクセスクラスの各メソッドを使用しなくてはなりません。お約束です。
データベースアクセスクラスを修正することもナシです。


お約束なんて、何かの前提の上にあるんだから、前提が崩れたらお約束も崩れちゃうんだよね。



引用:

各メソッドを使うかぎり、自由にコードを書いていいのですが例外処理についても同様に自由です。


ここ、わかりません。
普通、コーディング規約によって、同じようにコード化すると思います。あるところは「例外はすべて握りつぶして、True/False を返す」で、あるところは「例外で通知」だと、一貫性がないと思います。


引用:

コード:
     Catch ex As ApplicationException
         throw(ex.message)
     Catch ex As Exception
         throw(ex.ToString)
     End Try




ん???おかしくないですか?string を throw できましたっけ?
それはともかく、再投するなら、Throw だけです。これを Throw ex 等とすると、ここが例外の発生場所になってしまいます。

 また、この例であれば、try - catch の中で投げている例外を再投しているのですから、無意味です。
引用:

データベースアクセスクラスが何をして、戻り値が何で、どんな例外をThrowするのか
ソースを読めばわかりますがメンドクサイので
すべての例外をExceptionでCatchし最上位のコードまで例外を再Throwさせて最上位で処理するようにしています。


と、一致していません。
また、どんな例外を投げるかわからないからといって、すべての例外をキャッチする必要もありません。上に届かせたくない例外だけ、キャッチすればいいのではないですか?
 使う側は、例外が投げられることだけを知ればいいと思います。例外が投げられて、処理が中断してしまうとき、リソースの解放等が的確に行われるようにコーディングしてさえいれば、良いのではないでしょうか。
未記入
大ベテラン
会議室デビュー日: 2006/05/19
投稿数: 125
投稿日時: 2006-07-12 10:39
!?

例外処理について根本的な考えが間違ってました。

下位で発生した例外を上位に伝えるためには
Throw new ○○Exception("")しないといけないと思ってました。
オハズカシイ...アナガアッタラハイリタイ...

って事は下位で上位に伝えたい例外が発生したら
Catchして再Throwするか(このときはThrowと書くだけ)
Ctachせず何もしなければ上位に伝わるのですネ。

知らぬは一生の恥になるところでした。

private sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Try

Call SubTest1

Catch ex As ApplicationException
messagebox.show(ex.Message)
Catch ex As Exception
WriteLog(ex.ToString)
messagebox.show(ex.ToStrin)
End Try
End Sub

Private Sub SubTest1
Dim datarow as DataRow
Dim sql as new System.Text.StringBuilder(String.Empty)

’★Try〜Catchはいらない★
'Try

'予想しうる例外
If ("").Equals(Me.TextBox1.Text.Trim) Then
Me.TextBox1.Focus()
Throw New ApplicationException("テキストボックス1が未入力です。")
End If


'SELECT文を投げDataRow取得
sql.Append(" SELECT COUNT(*) FROM table1")
sql.Append(" WHERE field1 = '" & Me.TextBox1.Text.Trim & "'")
call データベースアクセスクラス.GetDataTable(datarow,sql.tostring)

’予想しない例外
if datarow is Nothing Then
Throw new Exception("DataRowオブジェクトが取れないよ。")
End If

’★Try〜Catchはいらない★
'Catch ex As ApplicationException
' throw New ApplicationException(ex.message)
'Catch ex As Exception
' throw New Exception(ex.ToString)
'End Try
End Sub
たつごろー
ぬし
会議室デビュー日: 2004/10/25
投稿数: 496
投稿日時: 2006-07-12 11:20
引用:
コード:

'予想しうる例外
If ("").Equals(Me.TextBox1.Text.Trim) Then
Me.TextBox1.Focus()
Throw New ApplicationException("テキストボックス1が未入力です。")
End If



このやり方を完全に否定するつもりはないですが、高コストな例外を使わなくとも、
コード:

If ("").Equals(Me.TextBox1.Text.Trim) Then
messagebox.show(ex.Message)
Exit Sub
End If


でいいんではないかと思います。
こういう書き方の様な、「条件に合わないとき、Returnしちゃうこと」を、ガードといいます。

引用:
コード:

’予想しない例外
if datarow is Nothing Then
Throw new Exception("DataRowオブジェクトが取れないよ。")
End If



これはオブジェクトが取れない、でただしいのですか?
このメッセージが、原因の追究の邪魔になるかもしれませんよ。

引用:

各メソッドの戻り値はBooleanで異常時True、正常時Falseを返します。
たとえばGetDataRowメソッドでDataSet.DataTable(0).Rows(0)をVyRef引数にセットしてくれるんですが
Rows(0) が NothingだったらTrueが返るんです。「True」です。「False」ではありません。


とあるので、この設計者は、
引用:
コード:

’予想しない例外
if データベースアクセスクラス.GetDataTable(datarow,sql.tostring) Then
Throw new Exception("DataRowオブジェクトが取れないよ。")
End If



と書いて欲しいのではないかと思います。

この書き方は、私はお勧めできないのですが、他のプログラム担当者はそうやっているのでは
ないかと想像しますよ。
この辺はチームで意識あわせをする必要を感じます。

ここで書いたコードは、意図的に質問者さんのコードを使う形にしています。


_________________
たつごろー http://www.codeseek.net

[ メッセージ編集済み 編集者: たつごろー 編集日時 2006-07-12 11:22 ]
1

スキルアップ/キャリアアップ(JOB@IT)