Jedes Mal, wenn ich zusätzliche Informationen zu einer Ausnahme bereitstellen muss, frage ich mich, auf welche Weise dies tatsächlich richtig ist .
Um dieser Frage willen habe ich ein Beispiel geschrieben. Angenommen, es gibt eine Klasse, in der die Abbreviation
Eigenschaft aktualisiert werden soll . Aus der Sicht von SOLID ist es vielleicht nicht perfekt, aber selbst wenn wir die Worker-Methode über DI mit einem Service übergeben würden, würde die gleiche Situation eintreten - eine Ausnahme tritt auf und es gibt keinen Kontext dazu. Zurück zum Beispiel ...
class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Abbreviation { get; set; }
}
Dann gibt es einige Instanzen der Klasse und eine Schleife, in der die Worker-Methode aufgerufen wird. Es kann das werfen 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
}
Die Frage ist: Wie fügt man das Person
oder sein Id
(oder irgendetwas anderes) hinzu?
Ich kenne die folgenden drei Techniken:
1 - Verwenden Sie die Data
Eigenschaft
Vorteile:
- einfach, zusätzliche Informationen einzustellen
- Es müssen keine weiteren Ausnahmen erstellt werden
- erfordert keine zusätzlichen
try/catch
Nachteile:
- kann nicht einfach in die integriert werden
Message
- Logger ignorieren dieses Feld und geben es nicht aus
- benötigt Schlüssel und Casting weil Werte sind
object
- nicht unveränderlich
Beispiel:
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 - Verwenden Sie benutzerdefinierte Eigenschaften
Vorteile:
- ähnlich wie das
Data
Eigentum, aber stark getippt - einfacher zu integrieren in die
Message
Nachteile:
- erfordert benutzerdefinierte Ausnahmen
- Logger ignoriert sie
- nicht unveränderlich
Beispiel:
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 - Schließen Sie die Ausnahme mit einer anderen Ausnahme ab
Vorteile:
Message
kann vorhersehbar formatiert werden- Logger geben innere Ausnahmen aus
- unveränderlich
Nachteile:
- erfordert zusätzliche
try/catch
- Inkrementelle Verschachtelung
- erhöht die Tiefe der Ausnahmen
Beispiel:
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...
}
- Gibt es noch andere Muster?
- Gibt es bessere Muster?
- Können Sie für alle Best Practices vorschlagen?
quelle
Antworten:
Data
FTW .Ihre "Contra":
-> Für Ihre Ausnahmetypen, sollte es einfach genug sein , außer Kraft zu setzen ,
Message
so dass es tut incorporateData
.. obwohl ich dies nur in Betracht ziehen würde , wenn dieData
die Botschaft ist .Googling für Nlog als Beispiel Ausbeuten :
Das scheint also einfach zu konfigurieren zu sein.
Huh? Legen Sie die Objekte einfach dort ab und stellen Sie sicher, dass sie eine verwendbare
ToString()
Methode haben.Außerdem sehe ich keine Probleme mit den Schlüsseln. Verwenden Sie einfach eine milde Einzigartigkeit und Sie sind gut.
Haftungsausschluss: Dies ist, was ich sofort aus der Frage ersehen konnte und worauf ich
Data
in 15 Minuten gegoogelt habe . Ich dachte, es ist milde hilfreich, also habe ich es als Antwort ausgegeben, aber ich habeData
mich selbst nie benutzt , also kann es gut sein, dass der Fragesteller hier viel mehr darüber weiß als ich.quelle
Warum wirfst du Ausnahmen? Damit sie gefangen und gehandhabt werden.
Wie funktioniert der Fang Code Arbeit aus , wie die Ausnahme behandeln? Verwenden Sie die Eigenschaften, die Sie für das Exception-Objekt definieren.
Verwenden Sie die Message-Eigenschaft niemals, um die Ausnahme zu identifizieren oder "Informationen" bereitzustellen, auf die sich ein potenzieller Handler verlassen sollte. Es ist einfach zu flüchtig und unzuverlässig.
Ich habe die "Data" -Eigenschaft noch nie verwendet, aber sie klingt für mich zu allgemein.
Wenn Sie nicht viele Ausnahmeklassen erstellen , von denen jede einen bestimmten Ausnahmefall identifiziert , woher wissen Sie, wann Sie die Ausnahme abfangen, für die "Daten" stehen? (Siehe vorherigen Kommentar zu "Nachricht").
quelle
Data
ist nutzlos für die Handhabung, aber wertvoll für die Protokollierung, um dieMessage
Formatierung der Hölle zu vermeiden .Ich mag Ihr drittes Beispiel, aber es gibt eine andere Möglichkeit, wie es codiert werden kann, um die meisten Ihrer "Nachteile" zu beseitigen.
quelle