- PR -

C# 戻り値の型を動的に変更することは可能ですか?

投稿者投稿内容
Atsushi.Eno
ベテラン
会議室デビュー日: 2003/04/23
投稿数: 60
投稿日時: 2005-05-01 04:08
引用:
逆じゃないの? 普通は制御できないから例外を投げるんだと思うけど。



何か変な解釈をしていると思うけど。先ほどのコメントでもそこはかとなく示唆したんですが、元のコードで、何でcatch(Exception)...が入っているのか、理由を考えましたか?本件メソッドの目的としてエラー文字列に関連する例外が「例外的である」場合の話なんてしていないんです。

本件メソッドの目的として予定されているものを「例外として投げる方が良い」というのは変です。それは、内部で起きた例外がこのメソッドで「制御できない」と勝手に見なしているように思えます。

先のコメントで書いていることは、例外だと、当該メソッドを呼び出した側がキッチリ例外を把握していないと(当該メソッド呼び出しだけを厳密にtry-catchで囲った上で、投げられる例外の種類をきちんと把握していないと)危ないでしょう、ということです。

引用:
もしプログラマが -1 がエラーをあらわすという仕様を知らなかったら、きっと後続の処理に戻り値 -1 を投入してしまうことでしょう。これは危険ですね。Atsushi.Eno さんの出力パラメータを使う方法も同じ危険性があります。出力パラメータが bool error などになっていれば、プログラマが仕様に気付く可能性は高いと思いますが、安全性では例外に劣ります。



ref/outが例外より安全性が低いというのは初耳です。ref/outの引数をメソッドに渡すときは、明示的にrefあるいはoutというキーワードを指定する必要があります。それはつまり、渡した変数に値が返ってくるということを意識させるに十分なものでしょう。あなた(誰だか知りませんが)はVBのERRみたいなものと同じようなものと考えているかもしれませんが、それよりはずっと安全です。

もちろん例外的状況を扱うという意味では、例外の方が安全ですよ。そのための例外なんですから。繰り返しますが、私は整数と文字列がどちらも予定された戻り値である場合にref/outがイイ、と書いています。
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2005-05-01 06:27
 私の意見は、未記入さんよりかなぁ?
 メソッド内でtry〜catchして、結果を上位に返すなら、「それに、throwは大きなパフォーマンスダウンにも繋がります。」というのは変ですよね?すでにthrowされているのですから。
 事前に検査を行うなら、あるいは例外を発生させないで処理することもできますが、例外が発生するのが例外的な状況なら、ほとんど必要ない検査を毎回実行するというのもパフォーマンスが悪いと思います。
 この例で発生する例外は、integer型の範囲を超える、ってやつですが、そうなると、後続の処理はできないはずです。ということは、判定処理を2重3重に行うことになります。だったら例外を発生させ、一番外側までジャンプさせるのが、結局パフォーマンスが優れることになると思います。あくまで、例外的な状況なのですから。


引用:

何か変な解釈をしていると思うけど。先ほどのコメントでもそこはかとなく示唆したんですが、元のコードで、何でcatch(Exception)...が入っているのか、理由を考えましたか?本件メソッドの目的としてエラー文字列に関連する例外が「例外的である」場合の話なんてしていないんです。


 いや、読みが足りないでしょう。もし、明確な意図を持って書いているなら、こういう質問はしないでしょう。また、文字列を返そうとはせず、数値を返すとか、外側で受けるとかにするでしょう。例外を理解しているなら、ね。
 例外を理解していないから、それを聞くための質問であり、質問するための急ごしらえのコードではないでしょうか。
_________________
Hongliang
ぬし
会議室デビュー日: 2004/12/25
投稿数: 576
投稿日時: 2005-05-01 09:25
引用:

Atsushi.Enoさんの書き込み (2005-05-01 04:08) より:

ref/outが例外より安全性が低いというのは初耳です。ref/outの引数をメソッドに渡すときは、明示的にrefあるいはoutというキーワードを指定する必要があります。それはつまり、渡した変数に値が返ってくるということを意識させるに十分なものでしょう。あなた(誰だか知りませんが)はVBのERRみたいなものと同じようなものと考えているかもしれませんが、それよりはずっと安全です。



VBのERRとやらがどんな機構なのかは知りませんが。
クロスランゲージできるのが.NET Frameworkの大きな特徴ですが、
VB.NETにおいて、C#でいうout/refは、宣言時にByRefキーワードを使用しますが、C#のように呼出時にキーワードをつける事はありません。
もちろんリファレンスを読めば分かる事ですが、やはり例外よりも確実性に劣る手法だと思います。
未記入
ぬし
会議室デビュー日: 2004/09/17
投稿数: 667
投稿日時: 2005-05-01 09:51
引用:

本件メソッドの目的として予定されているものを「例外として投げる方が良い」というのは変です。それは、内部で起きた例外がこのメソッドで「制御できない」と勝手に見なしているように思えます。


「(例外の発生が)予定されているかどうか」と「(例外処理を)制御できるかどうか」は独立した要素ですよ。例外の発生が予定されているからといって(下請けで)制御できるとは限らないです。

引用:

例外だと、当該メソッドを呼び出した側がキッチリ例外を把握していないと(当該メソッド呼び出しだけを厳密にtry-catchで囲った上で、投げられる例外の種類をきちんと把握していないと)危ないでしょう、ということです。


全然 危なくないです。プログラマが例外を把握していなかったら、より上位にその例外が伝播するだけでしょう。最終的にはアプリケーションが落ちることになると思いますが、それが危険かというと、それはアプリケーションの性質によりますね。世の中には、異常値で処理を続行してしまうよりもアプリケーションが落ちたほうが良い、というものがあるのです。私が実装しているものの多くもそうです。

「例外」とはそういった不安定状態での処理続行を抑制するためのものだと思います。明確に処理できるメソッドが例外を補足すべきで、意味も分からず勝手に補足して握りつぶしてはいけないのです。今回の例では、握り潰しによって呼び出し元は e.ToString() しか情報が得られなくなってしまっています。もし処理がもっと複雑で孫受け・曾孫受けがあったらどうしましょう。例外を投げてくれていれば スタックトレースを取得することもできて原因の分析もしやすくなります。

引用:

ref/outの引数をメソッドに渡すときは、明示的にrefあるいはoutというキーワードを指定する必要があります。


そうだったんですか。C# のことを知らないので勉強になります。( boolean ではなく bool と書くところまでは意識していたんですが、ちょっと油断してしまいましたね・・・そんな私は java 屋さん。)

引用:

ref/outが例外より安全性が低いというのは初耳です。


定説です。覚えておくと良いでしょう。

[ メッセージ編集済み 編集者: 未記入 編集日時 2005-05-01 09:51 ]
Atsushi.Eno
ベテラン
会議室デビュー日: 2003/04/23
投稿数: 60
投稿日時: 2005-05-01 12:01
最初の設問をすり替えて議論しているからおかしな話になるんです。

引用:

あまりよい例ではないかも知れませんが、
エラーがあった場合は、そのエラーの文字列をそうでない場合は
変数 finalValueを返すといった具合にしたいとき
、戻り値が
int に定義されているためにエラーになると思うのですが、

皆さん、このような場合はどうされているのですか?



もちろん「初心者です」って書いてあるから勝手に質問の意図を読み替えて回答しちゃえ、と思いたくなる気持ちは理解できますが、誰もがそう思っているこのスレッドの回答は、とても偏っているものに思えます。

私はこういう状況をいくつか思いつきます。たとえばSOAPサーバを実装していて例外時にサーバのログに例外を記録するのではなく(だけでなく)クライアントにSOAP Faultを返さなければならない場合がそうです。どこで投げられた例外か分からないもの(だから「安全でない」のです)を、最終的なcatchで拾うのはまずい状況だってたくさんあります[*1]。intの戻り値とは別に、エラーメッセージというか発生したExceptionをout/refで返すコードは、本当にコードを読んだり書いたりしたことがある人なら、目にしていてもおかしくないと思います。

そんなわけでalternativeを提示した時点で私の目的はほぼ達成されているんですが、誤解されたままでは信用されずにref/outが全く使われなくなってしまうかもしれないので、以下補足しておきます:

何度も書きますが、本当に例外的な状況で例外を使うな、なんて誰も書いてないんです。

本当に例外的な状況だ、というのなら、そりゃあ(Jittaさんの最初のコードの通り)最初からcatchしなければイイでしょう。

引用:
定説です。覚えておくと良いでしょう。



ref/outを知らなかった人が、ref/outより例外の方が安全だというのは定説である、と主張するんですか? そりゃあ例外的な状況を扱うのに、ref/outより例外の方が安全なのは間違いないですよ(また繰り返しですが)。

[*1] もちろんこういう場合InnerExceptionとしてもう1回例外を投げる方が一般的でしょうが、2回も例外を投げるようなパフォーマンスコストが受容されない場合もあります。
猫山みやお
大ベテラン
会議室デビュー日: 2004/09/09
投稿数: 119
投稿日時: 2005-05-01 12:58
.NETにはJavaの検査例外に相当する概念が無いって事が意外と知られてないようですね
.NET例外は投げたら投げっぱなしが基本です
あらかじめ想定される状況で例外を投げるのはお勧めできません
未記入
ぬし
会議室デビュー日: 2004/09/17
投稿数: 667
投稿日時: 2005-05-01 15:48
引用:

最初の設問をすり替えて議論しているからおかしな話になるんです。


最初の設問の話なんてしていませんよ。あなたが最初の設問に捕らわれているからおかしな話になっているだけじゃないかな。最初の質問には直後のレスで明確な回答がついているでしょう。Object 型を使用すれば不可能ではないが例外を使うべきである、と。

続く元質問者の書き込みでは「例外の意義・メリットが分からない。」となっていますから、このあとは(最初の質問を絶対要求仕様と捉えずに)一般的な例外のメリットを述べても おかしな話とは言えないと思います。

引用:

このスレッドの回答は、とても偏っているものに思えます。


例外を使えだけではなく、Object 型が利用できることが最初のレスで付いたことは、すばらしいことだと思いますけど、そんなに偏っていますかね?

引用:

本当にコードを読んだり書いたりしたことがある人なら、目にしていてもおかしくないと思います。(中略)誤解されたままでは信用されずにref/outが全く使われなくなってしまうかもしれないので、以下補足しておきます:


なんだか、ものすごい被害妄想に陥ってしまったのでしょうか。私は出力パラメータを使用する方法を完全否定したつもりはありませんよ。C# はほんのちょっとしか触ったことないですけど、Platform SDK の API 群を見ているので、出力パラメータでエラーをあらわす実装が存在することは目にしています。それを踏まえた上で、プログラマが自分で if文を書かないといけない点で、ダブルミーニングと同様の危険性がある、と述べただけです。それを、VB の ERR よりずっと安全だ! とか良く分からないあさっての方向に話を持って行っているのはあなたでしょう?

引用:

本当に例外的な状況だ、というのなら、そりゃあ(Jittaさんの最初のコードの通り)最初からcatchしなければイイでしょう。


意味のある finalValue を返すことができないという時点で、入力に対して出力が期待される関数にとって例外的な状況だと思いますけど。逆に言えば、意味のある値を返せるなら例外を握り潰しても良いケースもあります。たとえば、設定ファイルからポート番号を読み取って返すメソッドを設計したとしましょう。そのメソッドは設定ファイルが存在しないなどの理由で読み取れなかった場合には、デフォルトポートとして 80 を返すという仕様にしましょう。これなら例外を握りつぶしてもいいと思います。結果として意味のある戻り値を戻せているわけですから。

引用:

ref/outを知らなかった人が、ref/outより例外の方が安全だというのは定説である、と主張するんですか?


そうです。私は知ったかぶりしてるんですけど何か問題がありますか? ref/out とやらの構文詳細は知りませんが、それが出力パラメータであり、それをプログラマが判定する必要がある、ということは分かります(間違ってないですよね?)。なので、プログラマが判定する必要があるという点において同様の危険性がある、という主張は揺らがないと思いますけど。

引用:

.NETにはJavaの検査例外に相当する概念が無いって事が意外と知られてないようですね


ド素人な私でも、なぜか .NET の例外が Java の非チェック例外(RuntimeException)と同じように振舞うことを知っています。C# vs Java の比較記事で読んだんだったかな。で、それは知っているんですが、すべてが非チェック例外だとして、なぜ次のふたつが導かれるのかが理解できません。

引用:

.NET例外は投げたら投げっぱなしが基本です
あらかじめ想定される状況で例外を投げるのはお勧めできません


もしよろしければ、catch が強制されないことと、「投げっぱなし」「例外を投げるのはお勧めできない」の関連について教えていただけませんか。私が つたない C# のコードを書いたときは、リファレンスと睨めっこして必死に IOException などをキャッチしたものですが、これは .NET Framework の標準ライブラリ群の「例外を投げる」という実装がよろしくないということですか?
nanbu
大ベテラン
会議室デビュー日: 2004/08/19
投稿数: 178
投稿日時: 2005-05-01 20:37
引用:

もしよろしければ、catch が強制されないことと、「投げっぱなし」「例外を投げるのはお勧めできない」の関連について教えていただけませんか。私が つたない C# のコードを書いたときは、リファレンスと睨めっこして必死に IOException などをキャッチしたものですが、これは .NET Framework の標準ライブラリ群の「例外を投げる」という実装がよろしくないということですか?



南部です。

CLRでは、例外はアプリケーションエラーやシステムエラーを表現するものなので
基本的に業務フローから出るときに使用されます。
なので、業務フローではハンドリングせず「投げっ放し」です。
(もちろん、業務フロー外でハンドリングされるでしょうが)

また、業務フロー内で実行されるビジネスメソッドは、例外の定義により、
実行結果を「戻り値」で表現する必要があります。
よって、「例外を投げるのはお勧めできない」です。

以上が、CLRのデザインルールだそうです。

#StrutsにおけるActionの実装みたいなもんかと。

なので、try-catchやthrowによるフロー制御を行うため、
ビジネスメソッドから実行されるライブラリのメソッドは、
例外をスローことは未記入さんが述べられているような
メリットがあります(業務エラーへ変更)。

が、やはり余計な(キャッチすべきでない)例外をキャッチして、
ビジネスフローが継続してしまう危険性は存在します。

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