Я наткнулся на шаблон в кодовой базе, над которым я работаю сегодня, который первоначально казался чрезвычайно умным, потом позже довел меня до безумия, и теперь я задаюсь вопросом, есть ли способ спасти умную часть, минимизируя безумие.
У нас есть набор объектов, которые реализуют IContractObject
, и класс InvariantChecker
, который выглядит следующим образом:
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
}
}
Это используется для обеспечения относительно безболезненной проверки согласованности состояний во время выполнения. Я этого не писал, но изначально это казалось довольно крутой идеей.
Однако проблема возникает, если Foo.DoWork
выдает исключение. Когда генерируется исключение, вполне вероятно, что мы находимся в противоречивом состоянии, что означает, что InvariantChecker
также выбрасывает, скрывая исходное исключение. Это может происходить несколько раз, когда исключение распространяется вверх по стеку вызовов, при этом InvariantChecker
в каждом кадре скрывает исключение из кадра ниже. Чтобы диагностировать проблему, мне пришлось отключить бросок в InvariantChecker
, и только тогда я смог увидеть исходное исключение.
Это очевидно ужасно. Тем не менее, есть ли способ спасти хитрость оригинальной идеи, не получая ужасного поведения, скрывающего исключения ?