概要
ネット上にあるサンプルでは、よく例外が省略されている事があります。
しかし、あまり例外の扱い方で参考になる実装はなかったりします。
目的が達しているからと、記載されている内容を過信し、そのまま転用してしまうと、後々トラブルになる可能性が高まります。
又、ライブラリなどの提供側を作る際にも同じ事が当てはまり、利用されるシーンを限定できないため、さらに想定外はつきものになります。
いつどこで発生した例外かをできるだけ正確に把握して完成度を上げたいところですが、発生状況を特定するのはなかなか難しいものです。
そもそも、例外は起きない様に実装すべきであり、Debug.Assert() や IFで動作条件をきっちり処理すべきことです。
プログラムを書く上で、必要なクラスやメソッドを呼び出す中で
どうしても例外処理は必要になってきます。
ここではライブラリ実装や一般プログラムを作るうえで、 例外構文としてよく使う try – catch における
入れておくと、あとあと助かる、お得な実装を紹介します。
実装
.NET 4.0 以上 C# のコード例です。
Intellisense上で 扱いやすいように、コードのコメントに使用例を付けました。
実装サンプルは コメントにあります。
// ExceptionExtension.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
namespace System.Diagnostics
{
/// <summary>
/// デバッグ中に例外が出た場合は、一度ブレイクさせる
/// </summary>
/// <example>
/// よくネットで見かける、だめな実装。
/// <code>
///public int ExecuteNgCase()
///{
/// int a = 0;
/// int b = 1000;
/// int result = -1;
/// try
/// {
/// result = b / a; // 0除算例外が出る
/// }
/// catch { } // 握り潰し
/// // もしくは下記でもほぼ同じ効果
/// //catch (Exception)
/// //{ }
///
/// return result;
///}
/// </code>
///
/// TraceBreak 使用例
/// テスト中、単体実装の確認中に問題をすぐ発見できる利点がある
/// <code>
///public void ExecuteCase2()
///{
/// var testFile = @".\TraceData.txt";
/// var msg = "トレースログだよ";
/// try
/// {
/// using (var writer = File.AppendText(testFile))
/// {
/// writer.WriteLine("[TRACE]:{0}:{1}", DateTime.Now.ToString(), msg);
/// }
/// }
/// catch (IOException iex)
/// {
/// // 例外をログに出す。デバッグ中はブレイク
/// iex.TraceBreak("[Log file error!]");
///
/// throw; // 上位に例外をスローする
/// }
///}
/// </code>
/// </example>
public static class ExceptionExtension
{
/// <summary>
/// 例外メッセージの出力(Debug.Print)及び、デバッグ中はブレイクする
/// </summary>
/// <param name="ex">例外データ</param>
/// <param name="markString">マーク文字列</param>
/// <param name="category">出力を編成するために使用されるカテゴリ名</param>
/// <param name="force">ブレイク強制</param>
public static void DebugBreak(this Exception ex, string markString, string category, bool force = false)
{
Debug.WriteLine(string.IsNullOrEmpty(markString) ? ex.Message : string.Format("{0}:{1}", markString, ex.Message), category);
if (force || Debugger.IsAttached)
Debugger.Break();
}
/// <summary>
/// 例外メッセージの出力(Debug.Print)及び、デバッグ中はブレイクする
/// </summary>
/// <param name="ex">例外データ</param>
/// <param name="markString">マーク文字列</param>
/// <param name="force">ブレイク強制</param>
public static void DebugBreak(this Exception ex, string markString, bool force = false)
{
Debug.WriteLine(string.IsNullOrEmpty(markString) ? ex.Message : string.Format("{0}:{1}", markString, ex.Message));
if (force || Debugger.IsAttached)
Debugger.Break();
}
/// <summary>
/// 例外メッセージの出力(Trace.Print)及び、デバッグ中はブレイクする
/// </summary>
/// <param name="ex">例外データ</param>
/// <param name="markString">マーク文字列</param>
/// <param name="category">出力を編成するために使用されるカテゴリ名</param>
/// <param name="force">ブレイク強制</param>
public static void TraceBreak(this Exception ex, string markString, string category, bool force = false)
{
Trace.WriteLine(string.IsNullOrEmpty(markString) ? ex.Message : string.Format("{0}:{1}", markString, ex.Message), category);
if (force || Debugger.IsAttached)
Debugger.Break();
}
/// <summary>
/// 例外メッセージの出力(Trace.Print)及び、デバッグ中はブレイクする
/// </summary>
/// <param name="ex">例外データ</param>
/// <param name="markString">マーク文字列</param>
/// <param name="force">ブレイク強制</param>
public static void TraceBreak(this Exception ex, string markString, bool force = false)
{
Trace.WriteLine(string.IsNullOrEmpty(markString) ? ex.Message : string.Format("{0}:{1}", markString, ex.Message));
if (force || Debugger.IsAttached)
Debugger.Break();
}
}
}

