我在今天工作的代碼庫中遇到了一個模式,最初看起來非常聰明,後來讓我瘋了,現在我想知道是否有辦法在最小化瘋狂的同時拯救聰明的部分。使用IDisposable檢查約束 - 瘋狂還是天才?
我們有一堆的實施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
中的拋出,然後才能看到原始異常。
這顯然很糟糕。然而,有沒有什麼辦法可以挽救原創想法的聰明,而不會產生可怕的異常隱藏行爲?
這是可怕的。 – jason 2011-03-07 16:46:53
是不是有一條規則,即析構函數應該盡其所能避免拋出異常? – driushkin 2011-03-07 17:11:52
這是IDisposable濫用後果的一個很好的例子。和CA1065,二合一。 – 2011-03-07 17:48:48