C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[4]: try...catch.... について


(過去ログ 144 を表示中)

[トピック内 11 記事 (1 - 11 表示)]  << 0 >>

■84328 / inTopicNo.1)  try...catch.... について
  
□投稿者/ 夜叉丸 (63回)-(2017/06/15(Thu) 09:04:49)

分類:[.NET 全般] 

try ... catch の代わりの使い方なのですが

例外で使用するもので条件判断等で使用するものではない。
と、言われたのですが、try catch で以下<<例1>>のように
使っていたのですが、それ以来<<例2>>のように
フラグの条件判断オンパレード状態になってしまいます。
ところどころフラグの設定忘れやforループの10段入れ子などでは
10個のフラグを用意してそこらじゅうで設定するという羽目に
スキル的なものなのですが、
自分にとってメンテナンスしにくく、もっとうまく作る方法があるかもしれませんが。
少し長めのコードになると、現状では以前より時間が3倍以上かかっています。

@やはり try ... catch は使うべきではないのでしょうか?
Aフォートランでは多用していましたけどgoto文を使いまくるのは正当でしょうか?
Bルールは守るべきなので、地道にするしかない?

雰囲気をわかってもらうために以下適当に作っていますので、
間違い等があるかもしれません。

<<例1>>
try {
 if() throw new Exception("A");
:
 for(int .....) {
  for(int .....) {
   if() throw new Exception("B");
    else {
     if() throw new Exception("C");
    :
   }
  }
 }
:
} catch(Exception ex)
{
  MessageBox.Show(ex.Message);
}

<<例2>>
bool error = false

if ()
{
 MessageBox.Show("A");
error = true;
}

bool threw = false;
if(!error) {
 for(int ....) {
  for(int ....) {
   if() {
    MessageBox.Show("B");
    threw = true;
   error = true;
    break;
   }
   else
   {
    if() {
     MessageBox.Show("C");
     threw = true;
     error = true;
     break;
    }
   }
  }
  if(threw) break;
 }
 if(!error) {
  :
 }
}



引用返信 編集キー/
■84329 / inTopicNo.2)  Re[1]: try...catch.... について
□投稿者/ ぽぴ王子 (43回)-(2017/06/15(Thu) 09:17:30)
ぽぴ王子 さんの Web サイト
No84328 (夜叉丸 さん) に返信

分岐ならgotoを使えばいいんじゃないッスかね。

と、それだけだと説明不足かもしれないので。

> 例外で使用するもので条件判断等で使用するものではない。

これはそのとおりだと思います。
例外はあくまで例外で、本来の使い方とはかけ離れた使い方をするのは
コードを読む上でもあまりいいとは思えないです。
(内部的に実行コストが高そうというのもありますが、それはそれとして)

あくまで個人的意見ですが <<例1>> の使い方は「なってない」と判断
すると思いますし部下がこういったコードを書いていたらやり直しさせる
と思います。

<<例2>> のフラグを使う方法も、夜叉丸さん自身が困っているように
多段ループなどになると破綻する可能性があると思います。

なので、とりあえずループを抜けるためであれば goto を使うのが最適かな
と思います。

http://ufcpp.net/study/csharp/st_branch.html#goto

ただ、例外と同様に goto も「使うべきではない」と言われることが多いです。
これは「変な使い方をするとコードの読みやすさに影響する等の理由がある
からだと思うのですが、逆に言えば「使うべきときは使う」でいいと思ったり
しますね。
例外も <<例1>> のような安直な(?)使い方はお勧めできませんが、そうする
しかない場面では使うこともやぶさかではないと思いますし。

あと、コードを投稿するときは「図表モード」にするといいです。
(投稿欄の本文の上に「投稿モード」というのがあります)

引用返信 編集キー/
■84330 / inTopicNo.3)  Re[1]: try...catch.... について
□投稿者/ ぶなっぷ (109回)-(2017/06/15(Thu) 09:45:55)
2017/06/15(Thu) 09:46:48 編集(投稿者)
要は、関数中で処理を中断せざるを得ない状況が発生し、
それが1つや2つのパターンではなく、多数存在するということかな?

この手の話は、はるか昔から、いろいろ議論されているように思います。
「これだ!」という決定的な方法がないのもまた事実です。
私が思いつく限りのパターンを並べてみます。

1) 関数の戻り値パターン
ErrType Func()    // ErrTypeはenum値
{
  if() return ErrType_A;
    :
  if() return ErrType_B;
    :
  if() return ErrType_C;
    :
}
などとして、関数の呼び出し側でエラー内容に応じた処理を行う

2) do_while パターン
do
{
  if() { エラー処理(); break;}
    :
  if() { エラー処理(); break;}
    :
  if() { エラー処理(); break;}
    :
} while(false);
1回しか通らない do while を途中でbreakして抜けるパターン

3) try catchパターン
try catchパターンもありだと思います。
ただし、私がやるなら「1) 関数の戻り値パターン」の変形です。
void Func()
{
  if() throw new Exception("A");
    :
  if() throw new Exception("B");
    :
  if() throw new Exception("C");
    :
}
とし、呼び出し側でtry catchする。
例外というのは、正常系の処理が続けらず、異常系の処理も関数内で
決定することができない場合に投げるものだと思うからです。

自関数内で異常系の処理を確定できるなら、そのようなものは、
例外処理しなくて良い気がします。

(例) ファイルアクセスエラー
File.Open()を呼んでファイルが見つからないと、FileNotFoundException
が発生します。これが、もし例外発生ではなく、関数内で「見つからない」
とメッセージボックスを表示する実装だったとすると、正常系で見つから
ないかもしれないファイルをオープンしにいったときに、メッセージ
ボックスが邪魔になります。

見つからないかもしれないファイルをオープンしにいくことが仕様上あり
得ないなら、関数内でメッセージボックスを表示しても良いわけですが、
その場合、いちいち内部で例外発生させて、catchしてなんてやるのは、
回りくどいわけです。

引用返信 編集キー/
■84332 / inTopicNo.4)  Re[1]: try...catch.... について
□投稿者/ shu (1030回)-(2017/06/15(Thu) 09:55:41)
No84328 (夜叉丸 さん) に返信
> try ... catch の代わりの使い方なのですが
> 
> 例外で使用するもので条件判断等で使用するものではない。
> と、言われたのですが、try catch で以下<<例1>>のように
> 使っていたのですが、それ以来<<例2>>のように
> フラグの条件判断オンパレード状態になってしまいます。
例2の判定変数名がerrorであることから処理しているのは
自前の例外を発生させているということでよい気がします。


> Aフォートランでは多用していましたけどgoto文を使いまくるのは正当でしょうか?
分かりにくくなる傾向があります。


> Bルールは守るべきなので、地道にするしかない?
ルールが決まっているなら守るしかないと思います。



> if() 
>   throw new Exception("B");
> else {
>  if() throw new Exception("C");
> }
if()
  throw new Exception("B");
if()
  throw new Exception("C");

でよいです。(trueのときに後ろに流れないのが明白なので)

例2も同様

引用返信 編集キー/
■84333 / inTopicNo.5)  Re[1]: try...catch.... について
□投稿者/ WebSurfer (1246回)-(2017/06/15(Thu) 11:12:36)
No84328 (夜叉丸 さん) に返信

> @やはり try ... catch は使うべきではないのでしょうか?

「よほどのことがない限り、アプリケーションで try-catch を書いてはいけません」と
いう意見があります。自分もそれに賛成です。

詳しくは以下の記事を見てください。

NETの例外処理 Part.1
https://blogs.msdn.microsoft.com/nakama/2008/12/29/net-part-1/

.NETの例外処理 Part.2
https://blogs.msdn.microsoft.com/nakama/2009/01/02/net-part-2/

Part. 1 に書いてありますが、例外(想定外の問題)と業務エラー(想定内の問題)は分
けて処置すべきだと思います。

想定内の業務エラーでも catch しないと補足できない場合はやむを得ないかもしれません
が、Exception ではなく特定の例外のみ catch すべきだと思います。詳しくは Part.2 を
見てください。


> Aフォートランでは多用していましたけどgoto文を使いまくるのは正当でしょうか?

goto 分はスパゲッティプログラムを作る元と昔から(?)言われていました。程度にもよる
でしょうが、少なくとも「使いまくる」のは避けるべきではないかと思います。


> Bルールは守るべきなので、地道にするしかない?

どういうルールなのか分かりませんが、もし try - catch を使うことを言っているのだとす
ると、使うこと自体は別にルールでもなんでもなくて、正しく使うルールを決めるという話
になると思いますが。


あと、今回の話とは直接関係ないかもしれませんが、Exception をキャッチするのは止めた
方がいいと思います。理由は上に紹介した記事を見てください。

.NET 4 からは破損状態例外は catch できなくなっているそうですが、「それでも Catch
(Exception e) を使用するのはよくない」ということについては以下の記事を見てください。

破損状態例外を処理する
https://msdn.microsoft.com/ja-jp/magazine/dd419661.aspx
引用返信 編集キー/
■84334 / inTopicNo.6)  Re[1]: try...catch.... について
□投稿者/ furu (101回)-(2017/06/15(Thu) 13:09:28)
No84328 (夜叉丸 さん) に返信

なぜ例外を使用したいのかって、多重ループ(switchも含む)を抜け出したいからです。
for,whileなどで、breakでは1つのループしか抜け出せません。
gotoや例外以外で、多重ループを抜け出せるのはreturnです。

処理を別なメソッド(C#だよね)に切り分けて対処します。

{
    if (!処理())
    {
        xxxxx
    }
}

bool 処理()
{
    if ()
    {
        MessageBox.Show("A");
        return false;
    }

    for(int ....) {
        for(int ....) {
        {
            if() {
                MessageBox.Show("B");
                return false;
            }
            if() {
                MessageBox.Show("C");
                return false;
            }
        }
    }

    //正常
    return true;
}


引用返信 編集キー/
■84337 / inTopicNo.7)  Re[1]: try...catch.... について
□投稿者/ Jitta (301回)-(2017/06/15(Thu) 16:25:59)
No84328 (夜叉丸 さん) に返信

bool flag = true;
for (int idx = 0; idx < X && flag; ++idx)
{


フラグの使い方の一例

引用返信 編集キー/
■84339 / inTopicNo.8)  Re[2]: try...catch.... について
□投稿者/ 夜叉丸 (64回)-(2017/06/15(Thu) 18:53:53)
皆さんありがとうございます。

try...catch... は使わずに自分に合った、
いろいろな方法を見つけるしかないみたいですね。

どうも、goto とか フラグ はみにくいので

この部分だけ文字列が返ってくればエラーとして表示処理する
みたいな別の関数?イベント?(名称わかりません)を作ると
new throw の代わりに return になるだけなので
でも、これも多重、複数になると全体の流れが見えにくくなるのかも、
また、他から呼ばれることがあるわけでもないのにサブルーチンに
するのはおかしいというルールとかありそうですが

private string Process1()
{
 if()
for()
if() return("A");

 return("");
}


にすれば自分にとってはまだコードがもともとと変わらないので、
処理の流れがわかりやすいのですが、どうなのでしょうか?


引用返信 編集キー/
■84342 / inTopicNo.9)  Re[3]: try...catch.... について
□投稿者/ Jitta (302回)-(2017/06/16(Fri) 10:37:49)
No84339 (夜叉丸 さん) に返信
> 皆さんありがとうございます。
>
> try...catch... は使わずに自分に合った、
> いろいろな方法を見つけるしかないみたいですね。


私は、throw new Exception が悪いとは思っていません。
しかし、try catch は避けるべきと思っています。

例えば、車のエンジンという、「車の部品」を考えてみます。
エンジンには回転数や温度といったプロパティがあります。
しかし、それらのプロパティに問題=エラーがあっても、
エンジンがユーザーに警告を発することはありません。
エンジンは問題があることをUIに通知し、
あるいはUIがエンジンを調べてエラーを検出して、
UIがユーザーに問題を通知します。

ソフトウェアのエラー通知も同じようにするべきです。
最初の投稿の例1で、なぜcatchして、メッセージボックスを出すのでしょうか。
この関数や、関数があるクラスが、ユーザーに直接通知する責務があるのでしょうか。

オブジェクト指向というと、クラスが〜とかの「名詞」が注目されがちですが、
オブジェクトには「目的」という意味もあります。
目的を達成するために何が必要か考えること、
すなわちオブジェクトに志向すれば、
もっと自然に考える事ができるのではないでしょうか。
引用返信 編集キー/
■84343 / inTopicNo.10)  Re[3]: try...catch.... について
□投稿者/ フェイタル (1回)-(2017/06/16(Fri) 10:48:12)
> また、他から呼ばれることがあるわけでもないのにサブルーチンに
> するのはおかしいというルールとかありそうですが

そんなことはないと思います。
「サブルーチン」を「メソッド」と言い換えれば、
一連の処理が1つの役割を行う単位と考えることができます。
それは他から呼ばれる・呼ばれないに関わらないものだと思います。

この方が、コードの可読性がよいと私も思います。
引用返信 編集キー/
■84366 / inTopicNo.11)  Re[4]: try...catch.... について
□投稿者/ 夜叉丸 (65回)-(2017/06/21(Wed) 16:24:53)
try ... catch ...
の使用は避けるようにします。

goto 文は見えにくくなるのであまり使いたくありません。

なので、サブルーチン・メソッドのやり方を使っていこうと思います。
ありがとうございました。
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -