- - PR -
C# 戻り値の型を動的に変更することは可能ですか?
投稿者 | 投稿内容 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2005-05-03 10:21
補足ありがとうございます。
デザインガイド ではなく デザインルール なのだそうです。やはり、.NET では例外の使用は禁じ手なんだと思います。仮に例外を使うとしても、すべて自分の責任範囲で、つまり自分で投げて自分でキャッチしなければいけないのでしょう。Atsushi.Eno さんが当初から言われていた「呼び出し元が限られていて十分に制御出来る場合にしか〜」というのも今では納得がいきます。 これは自分で例外をキャッチすることができない汎用ライブラリの設計には例外を使用することができないことを意味しますね。もし、Jitta さん, k-nak さん, 未記入などのように (.NET のデザインルールに照らして) 間違った例外の使い方をする人が作成したライブラリを使うと、アプリケーションが落ちます。みんな「例外をキャッチすべきではない」と考えているので、ライブラリ作成者が安易な気持ちで投げた IOException がアプリケーションを落としてしまうことになります。例外はとても危険な手法です。例外を使うくらいなら object 型を使ったほうがマシなのです。Jitta さんの提示してくれた例外を使ったコードは確かに可読性が高くシンプルですが、アプリケーションが落ちてしまうのでは意味がありませんよね。 .NET には結構、興味持っていたんだけどなあ。以前も Jitta さんにテキスト入力欄の幅に入力テキストを合わせこんで長体表示するサンプルコードとか見せてもらって感銘を受けたものだけど。やはり、私は Java から離れることはできそうもありません。Longhorn でランタイムの遅さが克服されたら移行してもいいかなと思っていたんだけど、そう簡単にはいかないようですね。 | ||||||||||||
|
投稿日時: 2005-05-03 11:27
そうですか? outでエラー情報を返す作りにしているということは、そのエラーが出ることが"想定の範囲内"(流行語か)ということですよね。 ですので、事前にその作業を行えるかチェックをするようにしておけば、作業を行うメソッド等にはoutパラメータは必要ないのではないでしょうか。 ファイルへのアクセスを例にとれば、もし通常の運用ではファイルにアクセスできないことは考えられないという場合は、ファイルアクセスのメソッド内でファイルにアクセスできなかった場合は例外を外に投げるのをためらうべきではありません。 なぜなら"ファイルにアクセスできない"というのは想定の範囲外だからです。 逆に通常の運用でファイルにアクセスできないこともありうるという場合も、ファイルアクセスのメソッド内でファイルにアクセスできなかった場合は例外を外に投げるべきです。 想定されている"ファイルにアクセスできない"という状態かどうかのチェックとファイルへのアクセスを同じメソッドで実装するべきではないからです。つまりファイルアクセスのメソッド自体は失敗することは想定していないということ。 想定の範囲内とか範囲外とか書きましたけど、極端に言えば「try-catchを書いているということは、それを想定しているということじゃないか」ということになるかもしれませんが、if文のような条件分岐のように使わないという意識でいいんじゃないですかね。 | ||||||||||||
|
投稿日時: 2005-05-03 12:24
南部です。 デザインルールと記述したのは私なので、、、 引用部内の次のものは間違いです。 1..NET では例外の使用は禁じ手 2.自分で投げて自分でキャッチしなければいけない 3.汎用ライブラリの設計には例外を使用することができない 4.これらを論拠に導いたもの .NETとJavaでは例外の取り扱いが違うとはいっても、業務エラーか例外かをハンドリングする点でそんなに変わりません。(例外はアプリケーションエラーもしくはシステムエラーを指す) Javaでは、throws IOException のようにコンパイラレベルでハンドリングを強制できるだけです。 例えば、ログインメソッド(ビジネスメソッド)の場合 Javaでは、 public void login(引数) throws LoginException; のようなインターフェースになるに対し、 .NETでは、 public bool Login(引数); のようなインターフェースになります。 Javaでは、SQLExceptionがloginメソッド内でキャッチされ、 業務エラーであれば、LoginExceptionを生成しスローします。 (これは、呼び出し元に業務エラーがあったことの報告に過ぎません) そうでない場合、接続できない場合などのシステムエラーだった 場合、LoginException以外の検査例外はスローできないので、 RuntimeExceptionに変換しスローし、ビジネスフローを出ます。 (ビジネスフローでは、キャッチすべきではありません) 一方、.NETでは、SQLExceptionをLoginメソッド内でキャッチし、 業務エラーであればfalseを返します。 そうでない場合、接続できない場合などのシステムエラーだった 場合、そのまま例外を投げます。 (ビジネスフローでは、キャッチすべきではありません) #どっちも、取り扱いが違うだけでほとんど同じです そして、Loginメソッドは汎用ライブラリには含まれないでしょう。 だって、ビジネスメソッドですから。 これがデザインルールです。 なので、
間違っていません。(私が間違っていなければですが) | ||||||||||||
|
投稿日時: 2005-05-03 13:37
そうですね、ロックして、チェックをして、その戻り値をチェックして、処理を行って、ロックを解除して。 そうすればいいのはわかります。 しかし、ドキュメントに、「メソッドBを呼ぶ前には必ずメソッドAを呼んで返値をチェックしてください」と書くことを非常にあほらしく思う私もいるわけです。 なんだかCっぽいな…と。 そういう言語なんだから仕方ないんですけどね。 | ||||||||||||
|
投稿日時: 2005-05-03 14:52
普通は Java でも boolean login(...) にすると思います。私なら次のようにします。
与えられたユーザー名とパスワードが正しければ true を返します。与えられたユーザー名とパスワードが正しくなければ false を返します。正しいかどうか分からない場合は例外を投げます。正しいかどうか分からないというのは、たとえば、認証に使用しているユーザーエントリファイルやデータベースが破損か何かで読み取れないような状況です。この場合、正規ユーザーもログインできませんので、true を返すのも false を返すのもふさわしくないわけです。それと、login メソッド内全体を try-catch で囲んで LoginException(RuntimeExceptionの自作サブクラス)でラップしているのは login というメソッドの性質上デリケートそうだったからです。素の FileNotFoundException や SQLException がそのまま上位に伝播するのを見逃すと、ログイン機構の仕組みを外部に露呈することになる可能性があるからです。 | ||||||||||||
|
投稿日時: 2005-05-03 16:34
南部さんの例は、以下のような仕様変更が入ったときにJavaのアプローチのアドバンテージがはっきりしますね。
仕様変更: ログインに失敗したときは「IDまたはパスワードが違います」、「業務時間外です」などの失敗理由も通知するようにして欲しい。 私があえてDotNETでJavaっぽいアプローチを行う理由の一つです。(Javaと違ってコンパイラのサポートが得られない分、気をつけてコーディングする必要はありますが) | ||||||||||||
|
投稿日時: 2005-05-04 01:20
.NETは「何となく」というレベルでしか知識がなかったので、
非常に勉強になりました。Javaと比べ例外の概念が違うのですね。 | ||||||||||||
|
投稿日時: 2005-05-04 07:05
それじゃぁ、.NET Frameworkのデザインルールに従うと、こんな感じ?
・・・やだ ちなみに、Javaの経験はほとんど無い。 [ メッセージ編集済み 編集者: Jitta 編集日時 2005-05-04 07:06 ] [ メッセージ編集済み 編集者: Jitta 編集日時 2005-05-04 07:06 ] |