• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:複雑な条件の書き方)

複雑な条件で処理を分岐する方法はどうすべきか

このQ&Aのポイント
  • c#初心者の方が複雑な条件で処理を分岐する方法について質問されています。質問文章では、条件分岐のコードの見やすさや再利用性について悩んでいる様子が伺えます。しかし、条件分岐のコードが複雑化している場合には、メソッドに分割してみることで可読性を向上させることができます。具体的な改善案やコード例も提示されていますので、参考にしてみてください。
  • また、条件分岐のコードが非常に複雑になりやすいため、適切なインデントや括弧の位置を工夫することも重要です。ただし、やりすぎて逆に見にくくなってしまう可能性もあるため、バランスを考慮しながらコードを整形することが求められます。
  • 最後に、条件分岐のコードが細かく分離できず、再利用される場所がない場合には、メソッドに分割せずにインデントなどを駆使して整形する方法もあります。ただし、見やすさや可読性を重視する場合には、メソッドに抽出して再利用性を高めることが望ましいです。このような場合でも、各自のコーディングスタイルやプロジェクトのルールに沿って書くことが重要です。

質問者が選んだベストアンサー

  • ベストアンサー
  • kekyo0
  • ベストアンサー率62% (5/8)
回答No.6

最初の方の回答でもありましたが、やっぱりテスト可能性に着目するのが良いと思います。 今のままでは、漏れのないテストを行うのが、(このコード量にして)既に苦痛です。 #昔は書き方だけでパフォーマンスに影響がありましたが、今やそんな事を気にするのは #シェーダプログラムぐらいでしょう。 条件の判定を細かく分割するのは良いアイデアです。最も、分割すべき節は考える必要があります(その判定の意味が明確になるように分割することが重要だと考えます)。 そのように分割し、個々の式の「意味」が正しいかどうかを、ユニットテストでテストするようにします。 テストが通った個々の式を集成したテストを書く頃には、コード全体について安心感が得られるはずです。 既に見ているかもしれませんが、参考までに。 http://www.atmarkit.co.jp/fdotnet/nagile/nagile02/nagile02_03.html

koumei000
質問者

お礼

 ご指摘ありがとうございます。  NAgilerは初めて見ましたが、ためになりました。特にサイバラさんのは最高でした。  とりあえず、NAgilerは非常に有用だと思うのでこれから実践したいと思います。ありがとうございました。

その他の回答 (7)

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.8

ifの条件中に代入式を書けるのは、Cの特徴で、場合によってはすっきりとわかりやすく、また、「いかにもCのプログラム」という感じがあるのですが 例のように複雑になったら、そんなCらしさは捨てた方がいいです。 とりあえずは、別の言語のように「代入は文で、ifの条件式中に書けない」ものとして、条件を整理するのがいいのでは?

koumei000
質問者

お礼

 そうですよね。1つのステートメントにインクリメント程度ならまだしも、代入まで、それも複数あると読みにくいですよね。  日ごろからそんなコードにはならないように心がけてはいるので、自分は問題ないですが、他人さんの書いたコードだけはどうしようもないです。

  • wormhole
  • ベストアンサー率28% (1626/5665)
回答No.7

本題とは関係ありませんが、 > ユニットテストですか。魅力的ではあるんですけどね。一度はNUnitに手を伸ばそうとしたのですが、 > >「使い方がイマイチ、アセンブリがどうとか」 >→「ユニットテストが無いならstaticチェッカー(Contract)を使えばいいじゃない」 ユニットテストとstaticチェッカーは用途が違いますよ。 またユニットテストはNUnitなど使えば便利なのは確かですが別に必須というわけではないです。 要は作ったクラスやメソッドが仕様通りに動作するのか確認できればいいだけなんで。

koumei000
質問者

お礼

 ご指摘ありがとうございます。  いえいえ、バグを減らすためのものと、仕様を明記するためのものということは知っていますが、原因不明のバグが発生したときがあって、そういうのを見つけるために使おうかと(結局使えずにひたすらステップインの連続)。  原因は本来変化するべきタイミングで変数が変化していなかった(ちゃんと連動していなかった)事なのですが、これがまた厄介で、 「正常値 → 不正値」の変化(明示的な不正値への変化)なら、 (バグ要因の変数を変化させている部分だけ)ざっと挙動を追うだけで見つけられるのですが、 「正常範囲 → 別の正常範囲」の変化(暗黙的な不正値への変化)の変化は、何しろバグ要因の値が一切変化していないわけで、探すのに苦労しました。  この場合、「UnderLimit <= Value && Value <= UpperLimit」が常に満たされているかどうかを確認すればよいので、Invariantな契約を使えばすぐに発見できたんですね(「Invariant」は静的チェッカー使わなくても十分役に立つし、比較的簡単に作れるので属性を駆使して、何とかもどきを作りました)。  また何かありましたら、ご指摘お願いします。

  • hidebun
  • ベストアンサー率50% (92/181)
回答No.5

多分、私が書いたサンプルは、あなたのif文を読み違えているように思いますが、 それは難読だから、ということで(^^;) ともかく、trueになる条件をツラツラと書き連ねて行けば、どんなに条件が増えても、 怖くありません。

koumei000
質問者

お礼

 回答ありがとうございます。 > 多分、私が書いたサンプルは、 > あなたのif文を読み違えているように思いますが、  elseが使われていないので、検索を行う用な判定や、手前の判定でtrueの場合、後ろが例外をスローする場合があったりすればまずいかもしれません。 > ともかく、trueになる条件をツラツラと書き連ねて行けば、 > どんなに条件が増えても、怖くありません。  うまく使えば便利そうです。ただ、「&(&&)」を使う場合はfalseを返したほうがいい場合もあるかもしれません。

  • hidebun
  • ベストアンサー率50% (92/181)
回答No.4

判定を関数化するのは、良いアイデアだと思います。 気になるのは、条件に応じて、trueやらfalseやらをバラバラに返そうとしているところです。 if文の判定条件は少し変更するだけでバグになってしまうので、複雑な判定は避けたほうが良いです。 例えば「trueになる条件に着目する」という方針で検討してみては? 1つずつの条件を読むなら簡単で、どういう条件ならsatisfiedなのか?が明確になります 。 bool satisfied(...) {  bool ret = false; // 初期条件  // 以下、retをtrueにする条件文だけ書く  //必要に応じてsatisfied条件を説明する  if ( value1 < A ) {   ret = true;  }  //必要に応じてsatisfied条件を説明する  value1 = values[index]);  if ( B && (value1 == C) || C || D || E ) {   ret = true;  }  //必要に応じてsatisfied条件を説明する  value1 = values[value2];  if ( value1 == F ) {   ret = true;  } //上記のsatisfied条件の判定に引っかからなければ、falseが返る  return ret; } 無駄な判定を避けたいなら、 ret = true; return; としても良いです。 こうしておくと、判定の優先順位の変更が必要になった場合も、入れ替えにより、容易に対応できます。

koumei000
質問者

お礼

 回答ありがとうございます。 > 判定を関数化するのは、良いアイデアだと思います。  人に言われると思いつきでも嬉しいものですね。 > if文の判定条件は少し変更するだけでバグになってしまうので、 > 複雑な判定は避けたほうが良いです。 > 例えば「trueになる条件に着目する」という方針で検討してみては?  一考の価値はありそうです。参考にさせてもらいます。

  • jjon-com
  • ベストアンサー率61% (1599/2592)
回答No.3

質問文に掲載された3例の中では,   if ( value1 < A ) return true;   if ( !B ) return false;   value1 = values[index];   if (!(value1 == C || value1 == D || value1 == E)) return false;   value1 = values[value2];   if ( value1 != F ) return false;   return true; という,真偽が決定したものから次々と振り分けていくコードが一番わかりやすかったです。 メソッドにするか否かは別の問題で,上記コードを例えばbool satisfied;という論理型変数に対する真偽値設定に置き換えても,判定の読みやすさは変わらないでしょう。

koumei000
質問者

お礼

 回答ありがとうございます。 > 上記コードを例えばbool satisfied;という論理型変数に対する真偽値設定に > 置き換えても,判定の読みやすさは変わらないでしょう。  そんな感じのことをしたかったのですが、最初はgoto使わないと判定なら抜けられないと諦めていたのですが、elseを使えば何とかなりそうですね。  そうすると bool statisfied; if ( value1 < A ) satisfied = true; else {   if ( !B ) satisfied = false;   else   {     value1 = values[index];     if ( value1 != C && !D && !E ) satisfied = false;     else     {       value1 = values[value2];       satisfied = value1 == F;     }   } }  のようになるのですが、if, elseが深くなってしまうのが嫌い(elseで階層にするぐらいならreturnで抜けたい)な性分で、if(else)が3つも階層になっていると、こう、なんと言うか、もやもやすると言うか、うずうずするタイプなんです。  やっぱり何ともならないものなんですかね?

回答No.2

条件文は 命題が真の場合と偽の場合の2つにわけ、そのツリー構造で分けていきます。 そうすれば、抜けるケースがなくなります。   複雑になってもツリー構造がわかれば、絵がかけます。 また、これが大事ですが、抜ける落ちるケースがなくなります。 きれいに求めようとすると、抜ける落ちるケースが、出て、それのバグ取りに時間がかかってしまうことが一番の問題です。

koumei000
質問者

お礼

 回答ありがとうございます。  ツリー構造ですか。最近は意識したことなかったですね。今後気をつけようと思います。

  • wormhole
  • ベストアンサー率28% (1626/5665)
回答No.1

私ならユニットテストのやりやすさも考えてメソッド化します。

koumei000
質問者

お礼

 回答ありがとうございます。  ユニットテストですか。魅力的ではあるんですけどね。一度はNUnitに手を伸ばそうとしたのですが、 「使い方がイマイチ、アセンブリがどうとか」 →「ユニットテストが無いならstaticチェッカー(Contract)を使えばいいじゃない」 →「Expressには対応しておりません」 →「いいもん。自分で似たのを作るもん!(飽くまでお金払わない)」 →「ソースコードを読むためにkm(yacc)」 →「不可解なところでsyntax error」 →「レキサーは異常なし」 →「パーサを解読してやるぜ!」 →「高級言語とは思えぬ可読性」 →「とりあえず変数だけでも読みやすく」 →「とりあえずshift、reduceらしきものをメソッドに抽出」 →「―――見える!!」 →「ifがウルトラカオス」 →「OKWave行こうぜ!」 →「(今)やっぱり諦めようぜ!」  とりあえず、参考になりました。ありがとうございます。

関連するQ&A

専門家に質問してみよう