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?
źródło
Odpowiedzi:
Data
FTW .Twój „contra”:
-> Na swoim rodzaju wyjątku, powinien on być na tyle łatwe do zastąpienia
Message
, tak aby nie włączaćData
.. chociaż ja tylko uznałby to jeżeliData
jest wiadomość .Googling dla Nlog jako przykład daje :
Wygląda na to, że łatwo to skonfigurować.
Co? Po prostu zrzuć znajdujące się tam obiekty i upewnij się, że mają one użyteczną
ToString()
metodę.Poza tym nie widzę żadnych problemów z kluczami. Po prostu użyj łagodnej wyjątkowości i jesteś dobry.
Zrzeczenie się: To właśnie od razu mogłem zobaczyć z pytania i na co wpadłem
Data
w ciągu 15 minut. Pomyślałem, że jest to raczej pomocne, dlatego udzieliłem odpowiedzi, ale nigdy się nie wykorzystałemData
, więc może się zdarzyć, że pytający o tym wie o wiele więcej niż ja.źródło
Dlaczego rzucasz wyjątki? Aby je złapać i poradzić sobie.
Jak działa kod przechwytujący, jak obsługiwać wyjątek? Korzystanie z właściwości zdefiniowanych w obiekcie wyjątku.
Nigdy nie używaj właściwości Message do identyfikowania wyjątku ani do dostarczania „informacji”, na których powinien polegać każdy potencjalny moduł obsługi. Jest po prostu zbyt niestabilny i zawodny.
Nigdy wcześniej nie korzystałem z właściwości „Data”, ale wydaje mi się to zbyt ogólne.
Jeśli nie utworzysz wielu klas wyjątków, z których każda identyfikuje konkretny wyjątkowy przypadek, skąd wiesz, kiedy złapiesz wyjątek, co oznacza „Dane”? (Zobacz poprzedni komentarz do „Wiadomości”).
źródło
Data
jest bezużyteczny do obsługi, ale cenny do logowania, aby uniknąćMessage
formatowania piekła.Podoba mi się twój trzeci przykład, jednak istnieje inny sposób, w jaki można go zakodować, aby wyeliminować większość twoich „oszustw”.
źródło