トップ回答者
try catch 使用頻度について(使い方)

質問
-
例外処理 try catch の使い方について質問があります。
try-catchは、どうしようもない場合にのみ使用する物であり「通常は例外が発生しないように作るべきだ」と先輩にお聞きしました。
ですが、どうしても納得できず質問をしてみたのですが、あまり納得のできる回答を頂けませんでした。そこで、このコミュニティにいる方々にもお聞きしたいと思い投稿しています。
try-catchは、頻繁に使用してはダメだというルールなどあるのでしょうか?
WEBではそういった記載は見受けられませんでした。例えば、File.copyなど戻り値の定義はありませんが、例外処理は存在します。
https://docs.microsoft.com/ja-jp/dotnet/api/system.io.file.copy?view=net-5.0
そういった場合、File.copyを実施する前にファイルが存在するか?パスが存在するか?など、すべての例外をチェックしたうえでFile.copyを実施するべきなのでしょうか?
以下のコードで完結にまとめてしまえばいいと思ってしまいます。
もちろんエラー内容(例外処理)の詳細を知らなくてもいい場合です。try { File.copy( strPathA, strPathB ); } catch { // エラーメッセージなど. }
- 編集済み LvZ_012017 2021年5月19日 13:08
回答
-
.NET アプリの例外処置について Microsoft Bolg に書いてあったことを要約して紹介しておきます(Bolg は今はリンク切れです)。
(1) 予測可能で正しい業務フローに戻すことができる「業務エラー」(例:ユーザーの入力間違い)と、予測できないもしくは予測はできても何の対応もできない「例外」(例:DB サーバーダウン)を区別して対処。
(2) 「例外」はランタイムに拾わせてアプリケーションを停止させる。無かったことにして、ユーザが作業を続けられるようにすると、強制的に停止させるより好ましからざる状況に陥るかも(ユーザーが大事なデータを壊したりとか)。
(3) よほどのことがない限り try-catch は書かない。
(4) キャッチせざるを得ない場合でも Execption はキャッチしない。キャッチせざるを得ないとしても範囲を絞る。例えば DB 関係の例外が予測されるなら SqlException に限定して catch し、Number プロパティなどでエラーの内容を調べて対処するとか。
(5) 間違って補足してしまった例外は throw する。(注:catch ブロックでキャッチした例外を throw するとスタックトレースが途切れるので単に throw と書く)
(6) ユーザーへの通知が必要なら、集約的例外処置を利用する。
それから、.NET 4 からは破損状態例外は catch できなくなっているそうですが、「それでも Catch (Exception e) を使用するのはよくない」ということについては以下の記事を見てください。
破損状態例外を処理する
https://docs.microsoft.com/ja-jp/archive/msdn-magazine/2009/february/clr-inside-out-handling-corrupted-state-exceptions
自分が持っている Microsoft の本に、上に書いた原則に則ったサンプルが載っていたので紹介しておきます。
データベースに INSERT する際に PK 制約違反で発生する例外のみ catch して「業務エラー」(2 重登録)としてユーザーに再入力を促し、その他は再 throw してランタイムに拾わせてアプリケーションを停止させるというものです。
public bool InsertAuthors() { var connection = new SqlConnection("接続文字列"); var command = new SqlCommand("INSERT INTO authors VALUES ('172-32-1176', 'White', ...)", connection); try { connection.Open(); try { command.ExecuteNonQuery(); } catch(SqlException sqle) { if (sqle.Number == 2627) { return false; } else { throw; } } } finally { connection.Close(); } return true; }
以下の記事も参考になると思います。
例外の推奨事項
https://docs.microsoft.com/ja-jp/dotnet/standard/exceptions/best-practices-for-exceptions
- 回答の候補に設定 kumo-msftMicrosoft contingent staff, Moderator 2021年5月25日 8:07
- 回答としてマーク LvZ_012017 2021年6月25日 1:57
すべての返信
-
.NET アプリの例外処置について Microsoft Bolg に書いてあったことを要約して紹介しておきます(Bolg は今はリンク切れです)。
(1) 予測可能で正しい業務フローに戻すことができる「業務エラー」(例:ユーザーの入力間違い)と、予測できないもしくは予測はできても何の対応もできない「例外」(例:DB サーバーダウン)を区別して対処。
(2) 「例外」はランタイムに拾わせてアプリケーションを停止させる。無かったことにして、ユーザが作業を続けられるようにすると、強制的に停止させるより好ましからざる状況に陥るかも(ユーザーが大事なデータを壊したりとか)。
(3) よほどのことがない限り try-catch は書かない。
(4) キャッチせざるを得ない場合でも Execption はキャッチしない。キャッチせざるを得ないとしても範囲を絞る。例えば DB 関係の例外が予測されるなら SqlException に限定して catch し、Number プロパティなどでエラーの内容を調べて対処するとか。
(5) 間違って補足してしまった例外は throw する。(注:catch ブロックでキャッチした例外を throw するとスタックトレースが途切れるので単に throw と書く)
(6) ユーザーへの通知が必要なら、集約的例外処置を利用する。
それから、.NET 4 からは破損状態例外は catch できなくなっているそうですが、「それでも Catch (Exception e) を使用するのはよくない」ということについては以下の記事を見てください。
破損状態例外を処理する
https://docs.microsoft.com/ja-jp/archive/msdn-magazine/2009/february/clr-inside-out-handling-corrupted-state-exceptions
自分が持っている Microsoft の本に、上に書いた原則に則ったサンプルが載っていたので紹介しておきます。
データベースに INSERT する際に PK 制約違反で発生する例外のみ catch して「業務エラー」(2 重登録)としてユーザーに再入力を促し、その他は再 throw してランタイムに拾わせてアプリケーションを停止させるというものです。
public bool InsertAuthors() { var connection = new SqlConnection("接続文字列"); var command = new SqlCommand("INSERT INTO authors VALUES ('172-32-1176', 'White', ...)", connection); try { connection.Open(); try { command.ExecuteNonQuery(); } catch(SqlException sqle) { if (sqle.Number == 2627) { return false; } else { throw; } } } finally { connection.Close(); } return true; }
以下の記事も参考になると思います。
例外の推奨事項
https://docs.microsoft.com/ja-jp/dotnet/standard/exceptions/best-practices-for-exceptions
- 回答の候補に設定 kumo-msftMicrosoft contingent staff, Moderator 2021年5月25日 8:07
- 回答としてマーク LvZ_012017 2021年6月25日 1:57
-
(
Bolg→ Blog).NET アプリの例外処置について Microsoft Bolg に書いてあったことを要約して紹介しておきます(Bolg は今はリンク切れです)。
blogs.msdn.microsoft.com で公開されていた nakama さんの「とあるコンサルタントのつぶやき」のアーカイブ記事を拾い集めてみました。
同ブログの移転先は nakama.azurewebsites.net で、過去記事の一部は docs.microsoft.com にありますが、欠損しているものは Internet Archive に遺っていたものを拾いました。
㊟ が付いたアーカイブ記事は、ページのロード中に Esc キー等で読み込みを中断させないと、SkyDrive(現 OneDrive) 上に置かれた zip に遷移してしまいます。ご注意ください。
- 例外処理関連
- 2009/01/08 投稿:.NETとJavaの例外処理の違い(web.archive.com)
- 2008/12/29 投稿:.NETの例外処理 Part.1(web.archive.com)
- 2009/01/02 投稿:.NETの例外処理 Part.2(web.archive.com㊟)と
そのサンプル[ExceptionManagement_Part2.zip (135.0KB)] - 2009/01/18 投稿:.NETの例外処理 Part. 3(web.archive.com㊟)と
そのサンプル[ExceptionManagement_Part3.zip (0.6MB)] - 2009/01/23 投稿:.NET の例外処理 Part. 4(web.archive.com)
- エラー処理関連
-
2009/02/28 投稿:エラーチェックの体系的な分類と実装パターン(docs.microsoft.com)と
そのサンプル[InputValidationSample.zip (194.7 KB)]- 2009/02/28 投稿:Part 1. エラーチェックの体系的な分類方法(docs.microsoft.com)
- 2009/02/28 投稿:Part 2. 単体入力エラーチェックの実装パターン(web.archive.org)
-
2009/02/26 投稿:双方向データバインドによる単体入力エラーチェック(docs.microsoft.com)
- 2009/02/26 投稿:Part 1. 双方向データバインドの基本的な使い方(web.archive.org㊟)と
そのサンプル[TwoWayDataBindingPart1.zip (57.5 KB)] - 2009/02/26 投稿:Part 2. スマートクライアントにおける単体入力データ検証(web.archive.org㊟)と
そのサンプル[TwoWayDataBindingPart2.zip (98.5 KB)]
- 2009/02/26 投稿:Part 1. 双方向データバインドの基本的な使い方(web.archive.org㊟)と
-
- 編集済み 魔界の仮面弁士MVP 2021年5月20日 2:37
- 例外処理関連
-
LvZ_012017さん、こんにちは。フォーラムオペレーターのKumoです。
MSDNフォーラムにご投稿くださいましてありがとうございます。
ご質問いただいた件ですが、その後いかがでしょうか。
皆様から寄せられた投稿はお役に立ちましたか。
参考になった投稿には [回答としてマーク] をお願い致します。
設定いただくことで、
他のユーザーもお役に立つ回答を見つけやすくなります。
お手数ですが、ご協力の程どうかよろしくお願いいたします。MSDN/ TechNet Community Support Kumo ~参考になった投稿には「回答としてマーク」をご設定ください。なかった場合は「回答としてマークされていない」も設定できます。同じ問題で後から参照した方が、情報を見つけやすくなりますので、 ご協力くださいますようお願いいたします。また、MSDNサポートに賛辞や苦情がある場合は、MSDNFSF@microsoft.comまでお気軽にお問い合わせください。~