- - PR -
C# 戻り値の型を動的に変更することは可能ですか?
投稿者 | 投稿内容 | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2005-05-10 20:44
ぼのぼのです。
私の読んだ限り、論点を集約すると.NETのエラー通知には例外を使うべきか否かってことになるかと思うのですが、9ページにわたる議論の末、まだ結論は出ていないんじゃないでしょうか? 「想定の範囲」は結局アプリケーション(or 人?)に依存する、という話が出てましたが、例えばクラスライブラリの場合は一つのアプリケーションのことだけ考えればいい、ということにもなりません。 例えば、アプリケーションAから使用されるクラスライブラリAがあり、この中に数値形式の文字列をカンマ埋めする関数AddComma()があったとします。で、アプリケーションAでは「数値として認識できない文字列は0として扱う」という業務ルールがあったとします。すると、呼ばれる側、呼ぶ側のロジックは単純に考えて以下の3パターンになるかと思います。
さて、どれが正しいのでしょうか? @は想定範囲内のエラーの通知にも例外を使用する、という設計方針なのでAddComma()で入力が数値形式でない場合は例外をthrowします。Aの場合、AddComma()は入力文字列が数値形式であることを前提としているので、入力が数値形式でない場合は想定範囲外ということになり、@と同じく例外をthrowします。設計方針は違っても結果として呼ばれる側のソースコードは同じになります。 Bは「数値として認識できない文字列は0として扱う」という業務ルールをクラスライブラリ側で吸収しています。 私なら、このクラスライブラリがアプリケーションAのみ、もしくは同じ業務ルールが適用されるアプリケーションのみから使用されることが前提ならBにするでしょう。使う側のコードが一行ですみますから。しかし、このクラスライブラリが将来的に異なる業務ルールのアプリケーションからも使用される可能性があるなら@Aのどちらかにするでしょう。 [ メッセージ編集済み 編集者: ぼのぼの 編集日時 2005-05-10 22:12 ] | ||||||||||||||||
|
投稿日時: 2005-05-10 22:50
確かに、違うものだと思います。 ただ、それを、どこで実装するか。または、『切り替える責任を持つ』ものを実装するのか、と考えると、アプリケーションに依存するものではない、と思います。 例えば、1つのソリューションとして、データベースを使用するアプリケーションと、データベースを管理するアプリケーションがあるとします。このソリューションに、「選択されたデータベースに接続し、接続オブジェクトを返す」メソッド、‘DB接続メソッド’を作ります。 南部さんのおっしゃることは・・・ ※データベースを使用するアプリケーション →そのまま‘DB接続メソッド’を使う →メソッドからの例外はキャッチしない ※データベースを監視するアプリケーション →「選択されたデータベースに接続できるか検査し、booleanを返す」メソッド、‘接続検査メソッド’を追加する →‘接続検査メソッド’で事前に検査することで、‘DB接続メソッド’の例外を避ける というような作りになると思います。 そうすると、同じソリューションの中で、「データベースに接続する」という同じことを実行するために、別々の実装をしなければなりません。これは不便ですし、混乱します。デザインガイドやルールは、混乱を起こすものではないと思います。 例外によって通知するなら、使用するアプリケーションも監視するアプリケーションも同じ形で呼び出しができ、キャッチブロックの中の実装によって動作を変更するだけで済みます。 業務的に考えると、監視するアプリケーションでは、データベースに接続できないことは、とてもよくあり得ることだと思います。 使用するアプリケーションで、接続できないことは確かに致命的な例外、エラーでしょう。しかし、想定されない事態ではないと思います。同じマシンにインストールされているならともかく、違うマシンにインストールされているなら、経路が様々な要因で切れることは想定されていなければならないと思います。 例えば、1画面に10の項目があって、ユーザがこれらの項目に入力を行い、「登録」ボタンをクリックしました。しかし、データベースに接続できませんでした。ここで、「データベースに接続できないことは、アプリケーションとしては想定範囲外」として落ちてしまう(例外をキャッチしない)と、ユーザの入力は失われてしまいます。 # 一部、「継続」を選べる例外もありますけど # 逆にユーザは、「終了」と「継続」、どちらを選べばよいのか迷うと思う
ということで # 「ガイドラインがよくわからんぞ」と、MSDNをフィードバックするか? まとめて失礼 甕星さん>
えっと、その「入力値をチェックする処理」が、例外を返すのか、チェックメソッドとしてあらかじめ検査するのか、ということだと思うのですが??? _________________ | ||||||||||||||||
|
投稿日時: 2005-05-11 10:06
こんにちは。
正しいかどうかは分かりませんが、自分だったら「呼ばれる側(1)(2)」と「呼ぶ側(2)」を選びます。なぜかというと「呼ばれる側(1)(2)」「呼ばれる側(3)」にしても、「数値として認識できない」という条件と同時に、次の暗黙の条件が存在しているからです。 ・引数はnullであってはならない ・引数はDecimalの範囲を超えてはならない この条件が満たされなければ、どちらの関数にしても例外が発生します。 (VB.NETを良く知らないですが、CDec()ってDecimal.Parce()と同じですよね?) 自分であれば、「数値形式の文字列をカンマ埋めする関数」という仕様をもったメソッドを作ったときに上記件を考慮し、ライブラリのドキュメントには引数で渡す文字列はDecimalに変換できる形でなければいけない(というニュアンス)の一文を加えておきます。 もっと良いのは、無効な引数が渡された場合は、Decimalに変換する際に発生する3つの例外もドキュメントにあわせて記述しておきます。 そうすれば使う側は、呼び出す前に事前検査をおこなうでしょう。 自分は、提供側は前提が破られた場合は例外によって通知する方が確実であり、逆に要求側は例外が発生する要因が事前に分かるのであれば、事前検査すべきだと思っています。 (IsNumericが上記3つの例外発生要因を検査できるものなのかよくわかりませんが) また、今はライブラリの中(コード)が明らかになっていますが、完全にブラックボックスだった場合、上記件がドキュメントに記載されていなければ、「数値形式の文字列」という部分しか想定できないですが、やはり「呼ぶ側(2)」で実装です。 想定外の例外(未処理の例外)が発生した場合、そのままにしておくとアプリケーションが落ちてしまうということになりますが、未処理の例外に対しては、かならずUnhandledExceptionEventHandlerやThreadExceptionEventHandlerで受け取り(WinAplの場合)、ログを出力するなり、最終的にどうするか(続行するのか、終了するのか)といった判断をユーザーに促すようにしています(ここもアプリケーションの仕様によるけど)。 | ||||||||||||||||
|
投稿日時: 2005-05-12 07:07
南部です。
業務エラーは、業務フローに対してのエラールートを想定する以上、 アプリケーションに依存すると思うのですが、、、
同じソリューション内でも、ある機能を持つクラスを継承なり、委譲なりで機能を追加することってありませんか? > 例外によって通知するなら たしかに、業務エラーを「例外」で表すことは、コーディング上は可能です。 業務エラーを「例外」で表現すべきでない〜に関しては、既に出てますね。
まず、「投げっぱなし」「例外をキャッチしない」は、 まったく最後までキャッチしないとは言っていません。 「業務フロー内で」と明記しているはずです。 「ユーザが入力したデータをデータベースに登録する」という業務フロー内で、 私は、データベースに接続できなかった場合の業務エラールートは設計しません。 (想定できたとしても) それは、データベースに接続できることが前提だからです。 接続できなかった場合、例外がスローされ、 「ユーザが入力したデータをデータベースに登録する」という業務フローは終了です。 (業務フロー内ではキャッチしませんから) この業務フローはそれ以上の余計なことはしません。 後は、この「例外」受け取り、処理すべきところで処理すればよいです。 | ||||||||||||||||
|
投稿日時: 2005-05-13 19:33
南部さん>
何度も読み返して、1つわからないことがあります。わからないというか、認識がずれているのがここかな、と。 “業務フロー内で”と書かれているのはわかっているのですが、では、“業務フロー外”とはどこでしょう? 私の中では、プログラム全体(アプリケーションの操作手順)が業務フローです。ですから、「業務フローの外で受ける」というと、プログラムのコーディング中では受けない、と解釈していました。CLRでは、そういう例外を受けて、「続行しますか?終了しますか?」と聞いてくれますから。その為、業務フローを続けることは、ユーザがアプリケーションの操作を続けられる状態を保つことと、ほぼ同じでした。 しかし、厳密に考えると、“業務{代行|支援}フロー”ですから、この中から本当の“業務フロー”である部分を切り分けるということですね? | ||||||||||||||||
|
投稿日時: 2005-05-14 02:12
あ、私も同じ疑問を持っていました。
このような表現が出てくるので、プログラムは複数の業務フローから構成される? ということなのかと考え直してしまったり。 私の場合は、業務フローという言葉をもっと広い範囲を指すコトバとして使います。業務フローってプログラム(つまりコンピュータシステム化された範囲)だけじゃなくて、人間、伝票回付、物品の入出庫など(コンピュータシステム化されていない部分も含め)業務全体の流れを業務フローって言いませんか? うちの会社だけかな。 -- タグが閉じてなかった・・・orz [ メッセージ編集済み 編集者: 未記入 編集日時 2005-05-14 14:44 ] | ||||||||||||||||
|
投稿日時: 2005-05-15 03:13
南部です。
!!!たしかに曖昧でした。 というか、私が使用を誤っているのかな? 私の認識、どういう意味で使用していたかを記述します。 #い、いまさら、、ですが、、、ごめんなさい。 「業務フロー」は、Jittaさん、未記入さんが おっしゃるとおり、業務全体の流れを指します。 「業務における始点から終点までの流れ」 が的確でしょうか。 そして「ビジネスメソッド」は「業務フロー」を実現する手段、行動です。 アプリケーションはこの「業務フロー」をプログラムによってシステム化 したものですが、システム化する「業務フロー」の規模によっては、 1つのメソッドや1つのアプリケーションで完結するものや、 たくさんのアプリケーションによって実現されるものあるでしょうし、 アプリケーションの処理が連続である場合もあるし断続であることも あるでしょう。 「業務フロー内」は、 ある業務を実現するビジネスメソッドにより構成されるフロー内であり アプリケーション内で業務フローの一部を表している(実装している)部分、 簡単な例ですが、、、
のような実装の場合、「業務フロー内」は 業務フロー開始メソッド内です。 Jittaさん、未記入さんのご指摘のとおり、実際はユーザが業務を 開始しようとアプリ(マシン?)を起動したときから既に業務フローは 始まっていますが、アプリ的には自分が実現している業務の実装部分、 つまり、ユーザのアクションなどによって要求される「業務的な処理」を 実装している「業務フロー開始メソッド内」に対して「業務フロー内」 という言葉を使用しました。 ボタン1をクリックし、ボタン2をクリックするという操作である 業務フローの場合、業務フローはそれぞれのハンドラで断続的に実行される 業務的な処理のフローということになります。 例外発生時(MyApplicationException)は、通常、集約エラーハンドラで、 処理されると思いますが、ボタン1クリック時の例外発生時に特有の処理を させたい場合、button1_Click内でMyApplicationExceptionをキャッチするのも 「私は」ありだと思っています。 「業務フロー開始メソッド」 がデータベースに接続されていることを 前提としていた場合(処理2でデータベースアクセス)、たしかに、 「データベースに接続できないという例外」は想定できます。 が、この場合、この業務フロー内でキャッチすべきではありません。 言い換えれば、この業務フロー内で「データベースに接続できない」に 対する業務エラールートを作成すべきではありません。 (データベースに接続されていることを前提としていた場合ですので) この業務フローをWebアプリケーションとして実行する場合、エラーログを 出力し、ユーザに適切なメッセージを表示するでしょう。 Windowsアプリケーションの場合、「接続できない例外」に対する処理として 「業務フロー開始メソッド」の外でキャッチし、接続設定ダイアログを 表示するというのもアリじゃないかと、、、。 #語句の使用が不適切だったら教えてください。 #そもそも、認識が誤りという可能性は大いにありますが。 | ||||||||||||||||
|
投稿日時: 2005-05-23 21:39
『.NET エンタープライズ Web アプリケーション開発技術大全 Vol.3 ASP.NET 応用編』は買っていなかったので、買ってきました(間違ってVol.2を2冊買ってしまった(;_;))。で、4章を何度か読んだのですが。。。
この中で、“業務ロジック”は、南部さんがおっしゃるような形で定義されているようです(図4-11など)。もしくは、“UI層”、“ビジネス層”、“データアクセス層”をきちんと分けた場合、「データベースにアクセスできない」というケースは“データアクセス層”としては想定されていないので、例外として通知する、という形(図4-14など)でしょうか。ユーザ入力の妥当性については、UI層で検査し尽くしておき、ビジネス層へは妥当なデータしか渡すな、という考え方でしょう。入力として妥当なはずのデータなので、それが設定できないようなケースはアプリケーションエラーである、と。 しかし、とってもとっても混沌としているのが、P259でしょうか。
結局、『分類を的確に行』うのは、経験や勘に頼るしかないのでしょうか。頼るというか、それによって左右されるというか。 これについては、P253に書いてありました。
いやだから、そのエラーが「業務的か否か」の基準が欲しいんだって(^^;。データベースが動いていて当然と考えるのか、「マシントラブルやメンテナンス、その他なんやかんやで接続できない状況もあり得るが、数秒後あるいは簡単に行える行為によって回復可能かもしれない」と考えるかは、その設計者が出会ったトラブルの量や種別によって違ってくると思うんだけどなぁ。。。 または、業務設計を行う際に「できて当然」と考えるかどうか、という切り分け方をしています。そういうきり分け方をすると、「ユーザの入力は正しくて当然」になってきます。そうなってくると、入力値の組み合わせによるエラー以外はすべて例外として実装、みたいな考え方になってくるんですけど。極端な言い方をすると、スクリプトインジェクションや、クロスサイトスクリプトなどの入力も、例外としてはじく、と。で、これは“業務フロー”の中で受けてはいけない、と。もっとも、『「アプリケーション/システムエラー」を「業務エラー」に切り替えるコード』によって、業務エラーとするべきなのでしょうが、だとすると受けてはいけない例外を受けろ、と言っているわけで。ああ、「受けなかったことにする」のか。 う〜ん、難しいです。余計に混乱しました。。。 まぁ、Javaをやっている人にとっては、「検査例外は戻り値の一部で返せ。実行時例外だけを例外で返せ。」と言えばいいのかもしれないけれど。 何はともあれ、結果的にすべての例外を補足し、メッセージを変更しなければならないのは、P264あたりで遠回しに書いてあります。
_________________ |