例外に関する追加情報を提供する必要があるたびに、実際にこれを行う正しい方法はどれかと思います。
この質問のために、例を作成しました。Abbreviation
プロパティを更新するクラスがあると仮定しましょう。SOLIDの観点からは完全ではないかもしれませんが、DIを介してワーカーメソッドをいくつかのサービスで渡しても同じ状況が発生します-コンテキストが存在しないという例外が発生します。例に戻る...
class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Abbreviation { get; set; }
}
次に、クラスのインスタンスと、worker-methodが呼び出されるループがあります。それは投げることができStringTooShortException
ます。
var persons =
{
new Person { Id = 1, Name = "Fo" },
new Person { Id = 2, Name = "Barbaz" },
}
public IEnumerable<Person> GenerateAbbreviation(IEnumerable<Person> persons)
{
foreach (var person in persons)
{
try
{
person.Abbreviation = GenerateAbbreviation(person.Name);
}
catch(Exception ex)
{
// ?
}
}
// throw AggregateException...
}
public IEnumerable<string> GenerateAbbreviation(string value)
{
if (value.Length < 5)
{
throw new StringTooShortException(value);
}
// generate abbreviation
}
問題は:Person
またはId
(またはその他)を追加する方法ですか?
次の3つのテクニックを知っています。
1- Data
プロパティを使用
長所:
- 追加情報の設定が簡単
- さらに例外を作成する必要はありません
- 追加する必要はありません
try/catch
短所:
- に簡単に統合できない
Message
- ロガーはこのフィールドを無視し、ダンプしません
- キーとキャストの値が必要です
object
- 不変ではない
例:
public IEnumerable<Person> GenerateAbbreviation(IEnumerable<Person> persons)
{
foreach (var person in persons)
{
try
{
person.Abbreviation = GenerateAbbreviation(person.Name);
}
catch(Exception ex)
{
ex.Data["PersonId"] = person.Id;
// collect ex
}
}
// throw AggregateException...
}
2-カスタムプロパティを使用する
長所:
Data
プロパティに似ていますが、強く型付けされています- に統合しやすい
Message
短所:
- カスタム例外が必要
- ロガーはそれらを無視します
- 不変ではない
例:
public IEnumerable<Person> GenerateAbbreviation(IEnumerable<Person> persons)
{
foreach (var person in persons)
{
try
{
person.Abbreviation = GenerateAbbreviation(person.Name);
}
catch(Exception ex)
{
// not suitable for this exception because
// it doesn't have anything in common with the Person
}
}
// throw AggregateException...
}
3-例外を別の例外でラップする
長所:
Message
予測可能な方法でフォーマットできます- ロガーは内部例外をダンプします
- 不変
短所:
- 追加が必要
try/catch
- ネスティングを増やす
- 例外の深さを増やす
例:
public IEnumerable<Person> GenerateAbbreviation(IEnumerable<Person> persons)
{
foreach (var person in persons)
{
try
{
try
{
person.Abbreviation = GenerateAbbreviation(person.Name);
}
catch(Exception ex)
{
throw new InvalidPersonDataException(person.Id, ex);
}
}
catch(Exception ex)
{
// collect ex
}
}
// throw AggregateException...
}
- 他のパターンはありますか?
- より良いパターンはありますか?
- それらのいずれか/すべてのベストプラクティスを提案できますか?