Me encontré con un patrón en una base de código en la que estoy trabajando hoy que inicialmente me pareció extremadamente inteligente, y luego me volví loco, y ahora me pregunto si hay una manera de rescatar la parte inteligente mientras se minimiza la locura.Verificando las restricciones usando IDisposable - ¿locura o genio?
Tenemos un montón de objetos que implementan IContractObject
, y una clase InvariantChecker
que tiene este aspecto:
internal class InvariantChecker : IDisposable
{
private IContractObject obj;
public InvariantChecker(IContractObject obj)
{
this.obj = obj;
}
public void Dispose()
{
if (!obj.CheckInvariants())
{
throw new ContractViolatedException();
}
}
}
internal class Foo : IContractObject
{
private int DoWork()
{
using (new InvariantChecker(this))
{
// do some stuff
}
// when the Dispose() method is called here, we'll throw if the work we
// did invalidated our state somehow
}
}
Esto se utiliza para proporcionar una validación en tiempo de ejecución relativamente indolora de consistencia estado. No escribí esto, pero inicialmente me pareció una idea genial.
Sin embargo, surge el problema si Foo.DoWork
arroja una excepción. Cuando se lanza la excepción, es probable que estemos en un estado incoherente, lo que significa que el InvariantChecker
también arroja, ocultando la excepción original. Esto puede ocurrir varias veces a medida que la excepción se propaga por la pila de llamadas, con un InvariantChecker
en cada cuadro que oculta la excepción del marco a continuación. Para diagnosticar el problema, tuve que deshabilitar el lanzamiento en el InvariantChecker
, y solo entonces pude ver la excepción original.
Esto es obviamente terrible. Sin embargo, ¿hay alguna manera de rescatar la astucia de la idea original sin tener el comportamiento horrible de excepción?
Esto es horrible. – jason
¿No existe una regla según la cual los destructores deberían hacer todo lo posible para evitar lanzar una excepción? – driushkin
Es un bello ejemplo de las consecuencias del abuso identificable. Y CA1065, dos por uno. –