我正在實現一個類庫,並尋找一種方法來限制庫將分配給預設數量的給定類的實例數量。限制必須是機器範圍 - 一個簡單的static
計數器是不夠的,因爲這隻會計算調用過程中的實例。我想保留儘可能簡單的東西(沒有內存映射文件等)並且儘可能安全(沒有在臨時文件或註冊表中存儲計數器),因此決定嘗試使用全局共享信號作爲「計數器」全局類實例計數(使用信號量)
public class MyClass : IDisposable
{
// Limit to 10 instances
Semaphore m_sem = new Semaphore(10, 10, "SharedName");
public MyClass()
{
if(!m_sem.WaitOne(0))
{
throw new Exception("No instances free");
}
}
void IDisposable.Dispose()
{
m_sem.Release();
}
}
這似乎工作正常。然而,如果Dispose()
不被調用,信號量永遠不會被釋放 - 實質上是「泄漏」實例。現在恕我直言IDisposable
是.NET最糟糕的部分之一 - 我看到遠遠比它更多的代碼using(...) {}
。更糟糕的是,當您使用IDisposable
作爲數據成員並且在您的應用程序的每個課程中都會看到「IDisposable癌症」傳播。
因此,我決定爲忘記using()的人實施完整的IDisposable
(反模式)模式。
public class MyClass : IDisposable
{
// Limit to 10 instances
Semaphore m_sem = new Semaphore(10, 10, "SharedName");
public MyClass()
{
if(!m_sem.WaitOne(0))
{
throw new Exception("No instances left");
}
}
~MyClass()
{
Dispose(false);
}
void IDisposable.Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
void Dispose(bool disposing)
{
if(disposing)
{
m_sem.Release();
}
else
{
// To release or not release?
// m_sem.Release();
}
}
}
一切都簡單而具有using
正確調用的時候,我鬆開semapore。但是,當被最終確定爲最後的手段時,據我瞭解,我不應該訪問受管資源,因爲銷燬順序不是固定的 - m_sem可能已被銷燬。
那麼,如何在用戶忘記using
的情況下釋放信號? (RTFM可能是一個有效的答案,但我希望避免)。就目前而言,「泄漏」的實例直到最終使用我的程序集的過程終止(此時我假設全局信號量被釋放)
或者的確有沒有更好的方法來做到這一點?
經過多次閱讀,即使MS自己的代碼似乎在這個問題上不一致。有時,實例在從終結器調用時,從不會在IDisposable數據成員上調用Dispose(),有時他們會這樣做。這一切都似乎基於MS自己的知識,包含什麼類的內幕正在做的事情 - 圍繞非託管的瘦託管包裝是安全的,而不是。還有另一個討厭IDisposable的原因,我猜想:)。 –