Щоразу, коли мені потрібно надати додаткову інформацію про виняток, мені цікаво, який спосіб насправді є правильним .
Заради цього питання я написав приклад. Припустимо, існує клас, в якому ми хочемо оновити Abbreviation
властивість. З точки зору SOLID, це може бути не ідеальним, але навіть якби ми пройшли метод робітника через DI з якоюсь службою, відбудеться та сама ситуація - виняток виникає, тому що для цього немає контексту. Повернутися до прикладу ...
class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Abbreviation { get; set; }
}
Потім є деякі екземпляри класу і цикл, де викликається метод-робочий. Це може кинути своє 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
(або що-небудь ще)?
Я знаю наступні три методи:
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...
}
- Чи є інші візерунки?
- Чи є кращі зразки?
- Чи можете ви запропонувати найкращі практики для будь-якого з них?