2007年4月27日金曜日

.NET 例外処理

私がNETを始めたのはVS2003です。
その頃に購入した本では例外処理は以下のように書かれていました。
・独自例外はApplicationExceptionから派生して定義する。
・業務エラーも例外として扱う。
つまり画面に配置されたコントロールの入力エラーも例外をスローしていたのです。

けれど現在は以下のような事を聞きます。
・独自例外はExceptionから派生して定義する。
・業務エラーは戻り値で表す。
それでも業務エラーも例外として扱うべき的な意見も聞きます。

なぜこのような事になったのでしょうか?
Microsoftは以前、以下のようなルールを採用していました。
・CLRがスローする例外は SystemException クラス (System) 派生の例外
・アプリケーションがスローする例外は ApplicationException クラス (System) 派生の例外
つまりシステム例外とアプリケーション例外を明確に区別し、アプリケーション例外である独自の例外を定義する際はApplicationExceptionから派生して定義すること推奨していたのです。

しかし、現在はこれを推奨していません。変わりにExceptionから派生させることを推奨しています。理由は.NET Framework クラスライブラリ 自身がこのルールを守れなかったからのようです。.NET Framework クラスライブラリ に用意されている例外の中にApplicationExceptionから派生しているクラスや、Exceptionクラスから直接派生しているクラスがあるのです。.NET Framework クラスライブラリ がルールを守れていない以上、ApplicationExceptionから派生させる意味はなくなります。

では現在の例外処理の一般的な実装方法はどうすればよいのでしょうか?
業務エラーは戻り値で返すのでしょうか?
それとも例外で返すのでしょうか?

業務エラーを例外で返す場合、
例えば例外をスローする可能性のあるメソッドを呼び出した際、例外が発生したとしても、呼び出し側で特に処理をしなくても例外はそのまま上位へと伝わり適切な箇所で処理が行われます。

業務エラーを戻り値で返す場合、
呼び出し側で戻り値を適切に判断し損ねてしまうと、アプリケーションは「一見」正常な動作を行いながら不整合な処理を行うかもしれません。また不具合の発見も困難になるかと思います。

業務エラーを例外で処理する方が利がありそうです。
ですが業務エラーを例外として扱うと違和感のあるメソッドもあります。例えばチェック系メソッドを考えた場合、入力エラーがあったコントロールにフォーカスを与えるなどよくあると思います。チェック系メソッド内で複数のコントロールの入力チェックを行ったとしましょう。入力エラーのあったコントロールにFocusを与え例外をThrowしメッセージは最上位で表示することになってしまいます。なんだか違和感がありませんか?この場合はチェック系メソッド内でメッセージを表示し該当コントロールにフォーカスを与え戻り値でエラーがあったフラグを返すとスッキリします。

現時点で、業務エラーを例外で返すか戻り値で返すかについてはCaseByCaseなのでしょう。事前にできるだけのチェックを行い、このチェックで発生する業務エラーは戻り値で処理。それでも発生するエラーは例外をスローします。

Public Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) 
Try
'入力チェックを行います。
If IsInputCheck = False Then
Return 
End If

'更新処理を行います。
Call Update()

Catch ex As Exceptionから派生した独自例外
MessageBox.Show(ex.Message,"システム名")
Catch ex As Exception
MessageBox.Show("予期しないエラーが発生しました。" & ex.ToString)
'ログを残す
Call CreateLog(ex.ToString)
End Try
End Sub

Private Function IsInputCheck() As Boolean
Try
If ("").Equals(Me.TextBox1.Text) Then
MessageBox.Show("TextBox1は必須入力です。","システム名")
Me.TextBox1.Focus()
Return False
End If
If Me.ComboBox1.SelectedIndex = -1 Then
MessageBox.Show("ComboBox1を選択してください。","システム名")
Me.ComboBox1.Focus()
Return False
End If
Catch ex As Exception
Throw
End Try
End Function

Private Sub Update()
Try
      If 登録しようとした主キーのIDが他のユーザによりすでに登録されていた場合 Then
Throw New Exceptionから派生した独自例外("すでに登録されています。")   
End If
     If 更新しようとした主キーのIDが他のユーザにより削除されていた場合 Then
Throw New Exceptionから派生した独自例外("すでに削除されました。")   
End If
'DB永続化処理を行います。
Catch ex As Exception
Throw
End Try
End Sub 


コードを見て何かお気づきでしょうか?
恥ずかしながらThrowしているだけなのに例外をCatchしています。
これは設計者の俺様ルールで
「デバッグするとき例外が発生したら最上位のCatchでコードが止まるのが不便」
という理由ですべてのコードにThrowするだけのTry~Catchを書かなくてはいけないのです。
これってどうなんでしょう?

2007年4月25日水曜日

.NET Framework3.0

.NET Framework3.0について調べるよう指示がありました。
指示がアバウトで、何を調べればよいのかよくわかりませんが
とりあえず調べてました。


.NET Framework 3.0 環境構築
実行環境/開発環境は下記のようですね。
・Windows Vista
・Windows Server 2003 Service Pack 1
・Windows XP Service Pack 2
 
 XPマシーン、2003Serverは.NET Framework 3.0 再頒布コンポーネントをインストールする必要がある。


.NET Framework 3.0は、.NET Frameworkのバージョンアップ版ではない

--引用--
.NET Framework 3.0は、その名前から従来の.NET Frameworkそのもののバージョンアップのように受け取られてしまいがちだが、実は違う。.NET FrameworkのランタイムであるCLRのバージョンも変わらず、.NET Framework対応言語(VB.NETやC#など)の言語拡張もない。
 では.NET Framework 3.0とは何かというと、以前はWinFXと呼ばれていた、.NET Framework 2.0上に位置する大きな意味でのフレームワークまたはクラスライブラリ郡といえるものだ。
 つまり、.NET Framework 2.0ベースで開発されたソフトウェアには、何の影響も与えることがない。Side-By-Sideにする必要さえない。ソフトウェアを.NET Framework 3.0対応にするということは、単純に追加されたクラスライブラリを利用するということにほかならない。


NET Framework 3.0で追加された機能
・Windows Presentation Foundation(WPF)
・Windows Communication Foundation(WCF)
・Windows Workflow Foundation(WF)
・Windows CardSpace(WCS)

WPFとは?
デスクトップコンポーネント。
ビオカードの3D機能を使ったプログラミングができる。
http://www.atmarkit.co.jp/fdotnet/special/dotnetfx3001/dotnetfx3001_02.html

WCFとは?
ネットワーク,IPC部分。
http://www.atmarkit.co.jp/fdotnet/wcf/wcf01/wcf01_01.html


WFとは?
ワークフロウ設計部分。
http://www.atmarkit.co.jp/fdotnet/special/winworkflow/winworkflow_01.html


WCSとは?
現行のパスワードに代わる認証の仕組み。
http://www.microsoft.com/japan/msdn/net/general/intronetfx30.aspx


ぼそっ
いったい何が知りたいのだろう?
何度も申し上げましたが
FrameWork2.0はWindowsVistaでも開発・実行に問題ありません。
レジストリの操作などでFrameWork2.0アプリがFrameWork3.0で正常に動作しないなど某ブログで書かれていましたが
そんなことしてないじゃないですか。
FrameWork2.0で開発してもFrameWork3.0で開発しても
そんな高度な事はしてないのに・・・
今後もそんな高度な事はしないのに・・・
何で何回も同じこと指示してくるのだろうか?

.NET スタートアップオブジェクトをSubMainにする

今更だけどメモ。
サンプル画面などを作るときついつい面倒なので、Formをスタートアップオブジェクトにすることがあります。
それをそのままコピペされるので、スタートアップオブジェクトは常にSubMainにするようにできる限り心がけます。

スタートアップオブジェクトをSubMainにするにはスタートアッププロジェクトのプロパティのアプリケーションタブで「アプリケーションフレームワークを有効にする」チェックをOFFにします。
Public Class Main
Public Shared Sub Main()
Application.Run(New Form1())
End Sub
End Class

.NET(Mobile) VisualStudio(Mobile) データグリッドの選択行のデータを取得する


Dim cm As CurrencyManager
cm = CType(Me.BindingContext(Me.DataGrid1.DataSource), CurrencyManager)
Dim rowView As DataRowView
rowView = CType(cm.Current, DataRowView)

.NET(Mobile)  カレントディレクトリのパスを取得する

現在実行しているディレクトリのパスを取得する。

Dim sCurrentDir As Strings
CurrentDir = _
System.IO.Path.GetDirectoryName _
([System].Reflection.Assembly.GetExecutingAssembly().GetModules(0).FullyQualifiedName)


'現在実行しているディレクトリにファイルがある場合は

Dim sFileName as StringsFileName = sCurrentDir & "\" & "ファイル名.xxx"

.NET(Mobile) VisualStudio(Mobile) Mapping

データベースのCUSTOMERテーブルに
CUSTOMERIDフィールドと
CUSTOMERNAMEフィールドがあったとします。

Dim sql As String
sql = "SELECT CustomerId, CustomerName FROM Customer"
Dim td as DataTable
td = 上記のSQLで取得したデータ

上記のSQLで取得したDataTableをComboBoxのDataSouceに設定しました。

ComboBox1.ValueMember = "CustomerID"
ComboBox1.DisplayMember = "CustomerName"
ComboBox1.DataSource = td

なぜかコンボボックスのドロップダウンには正常に値が表示されません。
Windowsアプリケーションでは上記で表示できます。

ComboBox1.ValueMember = "CUSTOMERID"
ComboBox1.DisplayMember = "CUSTOMERNAME"
とすると正常に表示できました。

DataGridのColumnStyleのMappingName等も同様です。
スマートデバイスではデータベースのフィールドと大文字小文字も一致しなければいけないのでしょう。

.NET(Mobile) DataTableのSelectメソッドで列の最大値が取得できない

モバイルでの開発は初めてなので戸惑うことがとても多いです。
環境
VS2005
OracleLite
モバイル
W-ZERO3(WindowsMobile5.0 VGA対応)
HP?(WindowsMobile5.0)
DT5200(WindowsCE)

データテーブルからID列が最大値のデータを取り出そうと下記のコードを実行しました。
Dim dt As DataTable
Dim row() as DataRowrow = dt.Select("ID=Max(ID)")

が!!
DataRow配列にはデータテーブルの全行が返されました。

なんでだよぉ・・・