Chaque fois que je dois fournir des informations supplémentaires sur une exception, je me demande quelle est la bonne façon de procéder.
Pour cette question, j'ai écrit un exemple. Supposons qu'il y ait une classe où nous voulons mettre à jour leAbbreviation
propriété. Du point de vue SOLIDE, cela pourrait ne pas être parfait, mais même si nous passions la méthode de travail via DI avec un certain service, la même situation se produirait - une exception se produit et il n'y a pas de contexte. Retour à l'exemple ...
class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Abbreviation { get; set; }
}
Ensuite, il y a quelques instances de la classe et une boucle où la méthode de travail est appelée. Il peut jeter leStringTooShortException
.
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
}
La question est: comment ajouter le Person
ou son Id
(ou autre chose)?
Je connais les trois techniques suivantes:
1 - Utiliser la Data
propriété
Avantages:
- informations supplémentaires faciles à définir
- ne nécessite pas de créer encore plus d'exceptions
- ne nécessite pas de supplément
try/catch
Les inconvénients:
- ne peut pas être facilement intégré dans le
Message
- les bûcherons ignorent ce champ et ne le jettent pas
- nécessite des clés et une conversion car les valeurs sont
object
- non immuable
Exemple:
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 - Utiliser des propriétés personnalisées
Avantages:
- similaire à la
Data
propriété mais fortement typé - plus facile à intégrer dans le
Message
Les inconvénients:
- nécessite des exceptions personnalisées
- l'enregistreur les ignorera
- non immuable
Exemple:
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 - Envelopper l'exception avec une autre exception
Avantages:
Message
peut être formaté de manière prévisible- les enregistreurs déchargent les exceptions internes
- immuable
Les inconvénients:
- nécessite supplémentaire
try/catch
- nidification increses
- augmente la profondeur des exonérations
Exemple:
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...
}
- Existe-t-il d'autres modèles?
- Y a-t-il de meilleurs modèles?
- Pouvez-vous suggérer les meilleures pratiques pour chacun d'entre eux?
la source
Réponses:
Data
FTW .Votre "contra":
-> Pour vos types d'exception, il devrait être assez facile de passer outre
Message
pour qu'il ne incorporerData
.. bien que je ne considère cela si l'Data
est le message .Googler pour Nlog comme exemple donne :
Il semble donc que ce soit facilement configurable.
Hein? Videz simplement les objets et assurez-vous qu'ils ont une
ToString()
méthode utilisable .De plus, je ne vois aucun problème avec les touches. Utilisez simplement un caractère unique et vous êtes bon.
Avis de non-responsabilité: c'est ce que j'ai pu voir immédiatement à partir de la question et sur quoi j'ai fait une recherche sur Google
Data
en 15 minutes. Je pensais que c'était légèrement utile, alors je l'ai présenté comme une réponse, mais je neData
me suis jamais utilisé , donc il se pourrait bien que le questionneur en sache beaucoup plus à ce sujet que moi.la source
Pourquoi jetez-vous des exceptions? Pour les faire attraper et manipuler.
Comment le code de capture détermine-t-il comment gérer l'exception? Utilisation des propriétés que vous définissez sur l'objet Exception.
N'utilisez jamais la propriété Message pour identifier l'exception, ni pour fournir des "informations" sur lesquelles tout gestionnaire potentiel doit s'appuyer. C'est tout simplement trop volatil et peu fiable.
Je n'ai jamais utilisé la propriété "Data" auparavant, mais cela me semble trop générique.
À moins que vous ne créiez de nombreuses classes d'exception, chacune identifiant un cas exceptionnel spécifique , comment savoir quand vous interceptez l'exception ce que les «données» représentent? (Voir commentaire précédent sur "Message").
la source
Data
est inutile pour la manipulation, mais précieux pour la journalisation pour éviter unMessage
formatage infernal.J'aime votre troisième exemple, mais il existe un autre moyen de le coder pour éliminer la plupart de vos "con".
la source