Za każdym razem, gdy muszę podać dodatkowe informacje na temat wyjątku, zastanawiam się, który sposób jest właściwy .
Na potrzeby tego pytania napisałem przykład. Załóżmy, że istnieje klasa, w której chcemy zaktualizować Abbreviation
właściwość. Z SOLIDOWEGO punktu widzenia może to nie być idealne, ale nawet gdybyśmy przeszli metodę roboczą za pośrednictwem DI z pewną usługą, wystąpiłaby taka sama sytuacja - występuje wyjątek i nie ma w tym kontekście kontekstu. Powrót do przykładu ...
class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Abbreviation { get; set; }
}
Następnie są pewne instancje klasy i pętla, w której wywoływana jest metoda robotnicza. Może rzucić 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
}
Pytanie brzmi: jak dodać Person
lub jego Id
(lub cokolwiek innego)?
Znam następujące trzy techniki:
1 - Użyj Data
nieruchomości
Plusy:
- łatwo ustawić dodatkowe informacje
- nie wymaga tworzenia jeszcze większej liczby wyjątków
- nie wymaga dodatkowych
try/catch
Cons:
- nie może być łatwo zintegrowany z
Message
- loggery ignorują to pole i nie zrzucają go
- wymaga kluczy i rzutowania, ponieważ wartości są
object
- niezmienne
Przykład:
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 - Użyj niestandardowych właściwości
Plusy:
- podobny do
Data
właściwości, ale mocno napisany - łatwiejsze do zintegrowania z
Message
Cons:
- wymaga niestandardowych wyjątków
- logger je zignoruje
- niezmienne
Przykład:
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 - Zawiń wyjątek innym
Plusy:
Message
można sformatować w przewidywalny sposób- programy rejestrujące zrzucą wewnętrzne wyjątki
- niezmienny
Cons:
- wymaga dodatkowych
try/catch
- zwiększa zagnieżdżanie
- zwiększa głębokość wyjątków
Przykład:
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...
}
- Czy są jakieś inne wzorce?
- Czy są lepsze wzory?
- Czy możesz zasugerować najlepsze praktyki dla któregokolwiek / wszystkich?