Cada vez que necesito proporcionar información adicional sobre una excepción, me pregunto cuál es la forma correcta de hacerlo.
Por el bien de esta pregunta escribí un ejemplo. Supongamos que hay una clase en la que queremos actualizar la Abbreviation
propiedad. Desde el punto de vista SÓLIDO, podría no ser perfecto, pero incluso si pasáramos el método de trabajo a través de DI con algún servicio, se produciría la misma situación: se produce una excepción y no hay contexto. De vuelta al ejemplo ...
class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Abbreviation { get; set; }
}
Luego hay algunas instancias de la clase y un bucle donde se llama al método trabajador. Se puede tirar el 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
}
La pregunta es: ¿cómo agregar el Person
o su Id
(o cualquier otra cosa)?
Conozco las siguientes tres técnicas:
1 - Usa la Data
propiedad
Pros:
- información adicional fácil de configurar
- no requiere crear aún más excepciones
- no requiere adicional
try/catch
Contras:
- no puede integrarse fácilmente en el
Message
- los registradores ignoran este campo y no lo vuelcan
- requiere claves y valores de fundición porque
object
- no inmutable
Ejemplo:
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 - Usar propiedades personalizadas
Pros:
- similar a la
Data
propiedad pero fuertemente tipado - más fácil de integrar en el
Message
Contras:
- requiere excepciones personalizadas
- el registrador los ignorará
- no inmutable
Ejemplo:
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 - Ajustar la excepción con otra excepción
Pros:
Message
puede formatearse de forma predecible- los registradores volcarán las excepciones internas
- inmutable
Contras:
- requiere adicional
try/catch
- aumenta el anidamiento
- aumenta la profundidad de las excepciones
Ejemplo:
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...
}
- ¿Hay otros patrones?
- ¿Hay mejores patrones?
- ¿Puede sugerir las mejores prácticas para alguno / todos ellos?
fuente
Respuestas:
Data
FTW .Tu "contra":
-> Para sus tipos de excepción, debería ser lo suficientemente fácil de anular
Message
de manera que hace incorporanData
.. aunque yo sólo consideraría esto si elData
es el mensaje .Googlear para Nlog como ejemplo arroja :
Entonces parece que es fácilmente configurable.
¿Eh? Simplemente arroje los objetos allí y asegúrese de que tengan un
ToString()
método utilizable .Además, no veo ningún problema con las teclas. Solo usa un poco de singularidad y estarás bien.
Descargo de responsabilidad: Esto es lo que pude ver inmediatamente de la pregunta y lo que busqué en Google
Data
en 15 minutos. Pensé que era un poco útil, así que lo expuse como respuesta, pero nunca me he utilizadoData
, por lo que bien podría ser que el interlocutor aquí sepa mucho más sobre esto que yo.fuente
¿Por qué lanzas excepciones? Tenerlos atrapados y manejados.
¿Cómo funciona el código de captura cómo manejar la excepción? Usar las propiedades que defina en el objeto Excepción.
Nunca use la propiedad Mensaje para identificar la excepción, ni para proporcionar "información" en la que pueda confiar cualquier posible controlador. Es simplemente demasiado volátil y poco confiable.
Nunca he usado la propiedad "Datos" antes, pero me parece demasiado genérica.
A menos que cree muchas clases de Excepción, cada una de las cuales identifica un caso Excepcional específico , ¿cómo sabe cuando capta la Excepción qué representan los "Datos"? (Ver comentario anterior sobre "Mensaje").
fuente
Data
es inútil para el manejo, pero valioso para iniciar sesión para evitarMessage
formatear el infierno.Me gusta su tercer ejemplo, sin embargo, hay otra forma de codificarlo para eliminar la mayoría de sus "estafas".
fuente