- ベストアンサー
C#初心者のためのParseとTryParseの実装方法
- C#初心者の方に向けて、ParseメソッドとTryParseメソッドの実装方法を解説します。
- intのように比較的簡単に解析できるものならParseメソッドを使用し、例外処理を追加することで解析を行えます。ただし、Color構造体のような複雑なものになる場合はTryParseメソッドも検討する必要があります。
- TryParseメソッドの実装方法としては、Parseメソッドをtryブロックで囲み、catchブロックで例外処理を行う方法や、privateなtryParseメソッドを作成し、それをベースにする方法があります。どの方法がベストかは悩ましいところですが、保守性やパフォーマンスを考慮して選ぶ必要があります。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
throw/catchにかかるコストを考慮/実測した結果であるなら案3でいいんじゃないかしら。 例外オブジェクトをnewするだけならさほどのコストはかからなさそうですし(念のため実測するが吉)。 new するコストがバカにならんなら: enum err_code { no_err, format, overflow, ... }; private static err_code tryParse(string text, out Color result) { ... } public static Color Parse(string text) { Color result; switch ( tryParse(text, out result) { case err_code.format: throw new FormatException(); case err_code.overflow: throw new OverFlowException(); ... } return result; } public static bool TryParse(string text, out Color result) { return tryParse(text, out result) == err_code.no_err; } とか。
その他の回答 (2)
- επιστημη(@episteme)
- ベストアンサー率46% (546/1184)
> ちょっと神経質になりすぎでしょうか? 実測してみてはいかがです? 僕なら bool TryParse(string test, out Color result) を実装し、 Color Parse(string test) { Color result; if ( TryParse(test, out result) ) return result; else throw new FormatException(); } かな。
お礼
回答ありがとうございます。確かにその方法もあるのですが、それでは「FormatException」以外の例外、つまり例えば「OverFlowException」も発生する可能性があるのにそれに対応できないことです。それで Exception tryParse(string text, out Color result) をベースにしようと考えました。 いまさらですが、このtryParseは名前か引数を変えるかしてpublicにしてもいいような気がするのですが、「例外が発生したことを戻り値や引数で表してはいけない」と言うような話も聞いたような覚えがあるので分からないです。 また、(Color構造体は変わらないでしょうが、それ以外で)後々に仕様が変わって、発生する例外が変わっても修正する部分はわずかです。多分この程度ならYAGNIと言われないと思うのですがどうでしょうか?
補足
言い忘れていました。例外が発生というのは「案2」を用いて、TryParseを実装した場合、そこで例外が発生し、その例外がハンドルされるという意味です。 記憶違いでなければ、例外処理は他の普通の処理( O(n^3), O(2^n) 程ではない処理)と比較するとべらぼうに遅かったと思います。 try { throw Exception } catch ( Exception ) { } これをリリースコンパイル(最適化オン)に設定して、forでまわしてみると、平均12msでした(ノートPCで、CPU: 2.40GHz×2)。
- επιστημη(@episteme)
- ベストアンサー率46% (546/1184)
どれも大差ないんじゃないかと。 パフォーマンスを気にするほど頻繁に呼ばれるとも思えないし。
お礼
回答ありがとうございます。 確かに”頻度”は高くないのですが、”一気”に使われる可能性があります。 例えばHtmlのようにバイナリデータに変換せずにそのままテキストデータとして保存する場合、それを読み込む際、それなりの量の(合計して10~20kB)文字列が入力されることを想定しているので、その際、こんなところで例外が連発していたら、それなりに速度が低下すると思います(1回当たり12ms換算で100回起れば1.2秒)。 0.5秒で遅いと思われる、1.0秒で不機嫌になる人続出、と聞きましたが、ちょっと神経質になりすぎでしょうか?
お礼
回答ありがとうございます。 案3でいいのですか。いえ、例外(またはその情報)を戻り値などで返すのは、(サンプルでもあまり、というか全然見ないし)ちょっと気が引けたので、悩んだ挙句質問に至りました。 もともと文字を解析している時点でかなりのコストがあることは承知の上なので、例外のインスタンス初期化のオーバーヘッドくらいは些細なことかと。 確かに列挙体を使えばより高速かもしれませんが、例外の方が可読性や、保守性がちょっと上かなと思ったのがあります(単純に列挙体が思いつかなかったのもありますが……)。 それと、もうひとつ。一時期、「何とかして例外を使わずにコードを書くぞ!」と変な方向にがんばっていた時期がありまして、そのときの失敗(主に保守性と拡張性の欠落)の経験から、そういう目的での列挙体の使用がはばかれるというのがあります。 一応、3,4つのサンプルで実測してみましたが、例外の無い場合は、案2の方が案3より高速(とはいっても数値ですらほとんど変わらず、体感時間に変化なし)で、20以上の例外があるようなら、案2の方が体感速度にも影響が出る程度の時間の遅れはありました。 無論、コピペの案1は(ちょっとだけ)高速ですが、修正が面倒でした。